leanprover/lean4:stable と leanprover/lean4:v4.0.0-m5 という名前のツールチェーンは同じもので、名前だけが違う。どちらも、https://github.com/leanprover/lean4/releases/expanded_assets/v4.0.0-m5 からダウンロードされる。が、elanはそれに気付かずに、重複コピーのディレクトリを作る。
対策は、lean-toolchain を手で書き換えること。
leanprover/lean4:stable と leanprover/lean4:v4.0.0-m5 という名前のツールチェーンは同じもので、名前だけが違う。どちらも、https://github.com/leanprover/lean4/releases/expanded_assets/v4.0.0-m5 からダウンロードされる。が、elanはそれに気付かずに、重複コピーのディレクトリを作る。
対策は、lean-toolchain を手で書き換えること。
lakeはnpmほどには洗練されてないみたいだ。現状では完全な自動ビルドは無理な気がする。原因不明な失敗をすることがある。
ビルドの手順は、原理的には次のようなことだと思う。
コマンドラインで:
> lake build -v | tee "$(date +%Y-%m-%d_%H-%M-%S)_build.log"
これは、Git BashでもPowershellでもOK。Powershellのteeは Tee-Object の別名だが特に問題ない。
Gig Bash:
Powershell:
# lean-build.ps1 lake build -v | tee "$(date +%Y-%m-%d_%H-%M-%S).lake-build.log"
Powershellでは、lakeからの出力がないとルグファイルが作られないが、Git Bashではサイズ0のファイルが作られる。
信用できるのは、gitコミットのハッシュ値だけ。./laka-manifest.json に正確なバージョン(ハッシュ値)が書いてある。
{"git": {"url": "https://github.com/mhuisi/lean4-cli", "subDir?": null, "rev": "5a858c32963b6b19be0d477a30a1f4b6c120be7e", "name": "Cli", "inputRev?": "nightly" } }
この例で:
git cloneしたコミットのハッシュ値は次のようにして求める。
$ git branch * master $ git rev-parse master ecad15071973627f08ce7af018100fdbee566654
lakeがダウンロードして ./lake-packages/ の下にいれたパッケージでは、HEADがデタッチされている。
$ git branch * (HEAD detached at 5a858c3) main $ cat .git/HEAD 5a858c32963b6b19be0d477a30a1f4b6c120be7e
HEADが指しているコミットは、たいてはタグが付いている。最後〈最新〉のタグがパッケージのリリースバージョンになっていることが多いが、いつでもそうとは限らない。タグよりハッシュ値ベースで確認する。
$ git tag | tail -1 v2.1.0-lnightly-2022-11-20 $ git rev-parse $(git tag | tail -1) 5a858c32963b6b19be0d477a30a1f4b6c120be7e
プロジェクトディレクトリ内で elan show すると、そのプロジェクトのツールチェーンがダウンロードしてないと即座にダウンロードをはじめる。困ったもんだ。
elan toolchain list を使うべし!
lake build しても必要ならダウンロードして、elanツールチェーンリストに追加する。
VSCodeも、Leanプロジェクトの.leanファイルを開いた時点で、elanによるツールチェーンのインストールとlakeによるビルドを始める。が、ビルドはなかなかうまくいかない。
variable (α : Type) variable (F G : α → Type) def f : (∀ x : α, F x × G x) → (∀ y : α, F y) := fun h : ∀ x : α, F x × G x => fun y : α => (h y).fst
関数ヘッドを変形すると:
variable (α : Type) variable (F G : α → Type) def f' (h : ∀ x : α, F x × G x) : (∀ y : α, F y) := fun y : α => (h y).fst
variableの包摂〈取り込み〉すると:
def f'' (α : Type) (F G : α → Type) (h : ∀ x : α, F x × G x) : (∀ y : α, F y) := fun y : α => (h y).fst
圏論的プロファイル形式を書くと:
f'' : (α : Type), (F G : α → Type), (h : ∀ x : α, F x × G x) |- (∀ y : α, F y)
内部的に次のように変形される。
f'' : (α : Type), (F G : α → Type), (h : (x : α) → F x × G x) |- (y : α) → F y
Lean 4ではキーワードを整理したらしく。
Leanマニュアルでは "object" も使っているが、混乱のもとなので「要素〈element〉」を使う。「インスタンス」も混乱のもとなので使わない。「型の要素」を使う。
型の要素が命題の証拠〈witness〉に対応する。次はセクションの定義:
variable (F : Type → Type) variable (s : ∀(X : Type), F X) #check s Nat
セクション s は、パイ型のセクション。このパイ型は型族(型引数を持つ型)の総称型/多相型と言っていい。セクションは総称型〈多相型〉の一般化要素になる。
要素はポインターで、一般化要素はセクション。
命題の型宇宙では:
命題〈型〉と証拠〈ポインター〉、あるいは証明〈関数〉を区別する。命題には命題演算〈コネクティブ〉があり、証明〈定理〉には証明のコネクティブがある。
証明〈計算〉から証明〈計算〉を作る手続き〈メタ計算〉を重視する構成的論理で考える。証明〈計算〉に関するメタ計算がリーズニング。
def f1 (n:Nat) (m:Nat) : Nat := n + m def f2 (n:Nat) : Nat → Nat := fun (m:Nat) => n + m def f3 : Nat → Nat → Nat := fun (n :Nat) => fun(m:Nat) => n + m def f4 : Nat → Nat → Nat := fun (n m:Nat) => n + m #check f1 #check f2 #check f3 #check f4 #eval f1 3 4 #eval f2 3 4 #eval f3 3 4 #eval f4 3 4
check による表示では:
ここで、アンダースコア始まり変数は、もとラムダ変数。シーケント記法だと:
つまり、フル・アンカリー化して表示する。だが、内部的にはフルカリー化している。
よって、内部的はすべての関数は同じ形式になっていて区别が付かない(名前が異なるだけ)。呼び出し形式も戻り値も同じになる。次の点が分かりにくい。
def s1 (n: Nat) : Nat := n + 1 def s2 : Nat → Nat := fun (n:Nat) => n + 1 #check s1 #check s2 def valAtZero (f:Nat → Nat) : Nat := f 0 def valAtZero2 : (Nat → Nat) → Nat := fun (f:Nat → Nat) => f 0 #check valAtZero #check valAtZero2 #eval valAtZero s1 #eval valAtZero s2 #eval valAtZero2 s1 #eval valAtZero2 s2
↑で、定義形式に関わらずフルカリー化関数が格納されて呼び出されることが分かる。表示においては定義形式の影響を受けるが、内部に格納されている関数自体は定義形式の影響を受けない。
そもそも、インラインで関数を書くときは、フルカリー化する以外の方法がない。
代表的かつ重要な問題:
ソルバーソフトウェア:
wt.exe が2箇所にあった。
が、C:\Users\m-hiyama\AppData\Local\Microsoft\WindowsApps\wt.exe は0バイトでダミーだった。
二番目のwt.exeは実体がある。他に、WindowsTerminal.exeもあるが何故か実行できない。わからん。
それとショートカットキー問題。Alt+Ctrl+B をMSYS2のBashターミナルに割り当てたが、firefoxにフォーカスのときに Alt+B でMSYS2のBashターミナルが起動される。わからん。
wt.exe(ダミー)へのリンクをデスクトップに作って、ALT+Ctrl+Tで起動するようにしたが、あいかわらず毎回プロセス起動になる。
暫定的解決
定義によって何が生成されるか? これも曖昧。
define function x:A := t
に対して、次の6つのモノが混合コンテキストに追加される。
これらの追加〈append〉のためには、validityが必要。
これらの検証〈チェック〉作業が終わると、コンテキストに追加されて、結果的にコンテキストが膨らむ。次の作業は、膨らんだコンテキストに基づいてなされる。
次のようにする。
他に、一般的同値関係は ~ で表す。
区別してない。
項構成問題に対して、順行ソルバーと逆行ソルバーがあり、ソルバーをプログラムとして作ることをソルバー・プログラミングと呼ぶ。特に、項が証明項のときの逆行ソルバーのプログラミングはタクティク・プログラミング。
宣言文が環境としての事実の宣言と、今後やることの予告の宣言がある。
declare defined succ: Nat |- Nat declare defining add: Nat, Nat |- Nat
自然言語風に書くと:
it's already defined succ: Nat |- Nat we will define add: Nat, Nat |- Nat
f: A |- B と f': |- (A → B) があるとき、a: |- A に対して、
f |→ f' というカリー化はコアージョンとして組み込まれている。その結果、カリー化したモノの名前はオーバーロードされる。
「CTRL+ALT+P」で Powershell だったのだが、この設定は:
デスクトップにある Gi Bash へのリンクには、「CTRL+ALT+S Shell」が定義されていて有効ではある。
以前、「CTRL+ALT+P」に Bash を指定していたが今は何も設定されてない。MSYS2の"MSYS2 MSYS" に「CTRL+ALT+B Bash」を指定してみた。が、これも毎回プロセス起動で、フォーカスだけチェンジが出来ない。Windowsの仕様が変わったようだ。
アプリケーション側で、フォーカスチェンジに反応しないと新プロセス起動となるのかも知れない。
久しぶりで色々忘れている。
src/Init/Notation.lean からの情報。
構文範疇precは項の優先度を表す値(の表現)のことで:
Swiftの演算子がよく整理されている。Leanの値は後で埋める。
演算子 | 説明 | 結合律 | 優先順位 | Lean |
<< | 左ビットシフト | 無結合 | 160 | |
>> | 右ビットシフト | 無結合 | 160 | |
* | 乗算 | 左結合 | 160 | |
/ | 除算 | 左結合 | 160 | |
% | 剰余 | 左結合 | 160 | |
& | ビットAND | 左結合 | 160 | |
+ | 加算 | 左結合 | 140 | 65 |
- | 減算 | 左結合 | 140 | |
縦棒 | ビットOR | 左結合 | 140 | |
^ | ビットXOR | 左結合 | 140 | |
< | 未満 | 無結合 | 130 | |
<= | 以下 | 無結合 | 130 | |
> | より上 | 無結合 | 130 | |
>= | 以上 | 無結合 | 130 | |
== | イコール | 無結合 | 130 | 50 |
!= | ノットイコール | 無結合 | 130 | |
~= | パターンマッチ | 無結合 | 130 | |
&& | 論理AND | 左結合 | 120 | |
二本縦棒 | 論理OR | 左結合 | 110 | |
?: | 三項条件 | 右結合 | 100 | |
= | 代入 | 右結合 | 90 | |
= | 乗算と代入 | 右結合 | 90 | |
---|---|---|---|---|
+= | 加算と代入 | 右結合 | 90 | |
&:&= | 論理ANDと代入 | 右結合 | 90 |
優先度のグループ分けは:
130代が混みすぎ。
演算子優先度〈prec〉は適切かどうかわからない。
infix:70 "←" => Nat.pow #eval 5 ← 2 -- 25 def sqPow (n:Nat) : Nat := n ← (n * n) #eval sqPow 2 -- 16