Library ssr_discharge
From mathcomp Require Import all_ssreflect.
move:
SSReflect で、move=> H は証明対象の命題から前提に移すものですが、 逆に、前提から証明対象の命題に移すのは move: H を使います。?Goal先ほどのセクションの説明と同じく、P -> P の証明ですが、 最初に Show Proof とすると、?Goal と表示され、 証明項はまったくできていないことがわかります。
move⇒ H.
Show Proof.
Show Proof.
(fun H : P => ?Goal)move=> H で、H : P を前提に移したところで Show Proof とすると、(fun H : P => ?Goal) となり、 引数Hを受け取る関数抽象が構築されることがわかります。
move: H.
Show Proof.
Show Proof.
[eta ?Goal]ここで move: H として、H : P を証明対象に戻したところで Show Proof とすると、 eta ?Goal と表示されます。 Display notations を無効にして Show Proof をやりなおすと、 (fun H : P => ?Goal H) と表示されます。 まずわかることは「戻す」というのは証明項が元に戻るわけではないことです。 実際には ?Goal が ?Goal H に変化する、つまり、戻したものを引数とする関数呼び出しが構築され、 関数部分が新しいゴールとなります。
move⇒ H.
move: H.
move⇒ H.
move: H.
Show Proof.
move: H.
move⇒ H.
move: H.
Show Proof.
(fun H : P => (fun H0 : P => (fun H1 : P => ?Goal H1) H0) H)意味もなく move=> H と move: H を繰り返してみると、証明項は (fun H : P => (fun H0 : P => (fun H1 : P => ?Goal H1) H0) H) となります。関数抽象と関数呼び出しが増えていることが分かります。 Coq が表示する前提と証明する命題は変わりませんが、 内部では証明項が(意味もなく)膨らんでいるわけです。
Restart.
Show Proof.
Show Proof.
?GoalRestart の後で Show Proof とすると、?Goal とだけ表示され、 今まで構築した証明項が消えていることが確認できます。
move⇒ H.
move: (H).
move: (H).
ここでは、H が前提に表示されたままになっています。
Fail move⇒ H.
ここで、さらに move=> H としようとすると、失敗します。
(Fail というのはコマンドを実行して失敗することを確認するコマンドです)
これは証明すべき命題 P -> P の左側を前提に H という名前で移す指示ですが、
H という名前はすでに前提に存在するので、Error: H is already used. というエラーになります。
move⇒ Ha.
ここで Ha という別の名前を使えば問題なく成功します。
move: (Ha).
move⇒ Hb.
move: (Hb).
move⇒ Hc.
move: (Hc).
Show Proof.
move⇒ Hb.
move: (Hb).
move⇒ Hc.
move: (Hc).
Show Proof.
[eta [eta [eta [eta ?Goal]]]]eta で表示されると中身がよくわからないので Display notations を無効にすると、 以下のようになります。
(fun H : P => (fun Ha : P => (fun Hb : P => (fun Hc : P => ?Goal Hc) Hb) Ha) H)このように move: と move=> を数回くり返して Show Proof とすると、 move: に指定した Ha, Hb, Hc を引数とする関数適用が構築されていることがわかります。
Restart.
move: 0.
move: 0.
nat -> P -> Pこのように、move: 0 として 0 を指定すると、証明すべき命題は P -> P から nat -> P -> P に変化します。 指定した 0 はどこにいってしまったのかというと、Show Proof でわかります。
Show Proof.
(?Goal 0)つまり、証明項は関数適用として構築され、その引数は move: に指定した 0 になっています。 ?Goal の型はまず 0 を引数としてとるので、nat の値を引数に関数型となります。 そのため、証明すべき命題は nat -> ... となっているのです。
Restart.
move: (1 + 2).
Show Proof.
move: (1 + 2).
Show Proof.
(?Goal (1 + 2))