Coq例: n + 0 = n でいろいろ

証明戦略unfoldとfoldの練習です。

Coq < Lemma pluszero: forall n:nat, plus n 0 = n.
1 subgoal

  ============================
   forall n : nat, n + 0 = n

pluszero < intros.
1 subgoal

  n : nat
  ============================
   n + 0 = n
pluszero < induction n.
2 subgoals

  ============================
   0 + 0 = 0

subgoal 2 is:
 S n + 0 = S n

まずnをnatの定義から帰納的に場合わけすると、nが0の場合とS mの場合とに分かれる。

Coq < Print nat.
Inductive nat : Set :=  O : nat | S : nat -> nat
For S: Argument scope is [nat_scope]

つづけます。

pluszero < unfold plus.
2 subgoals

  ============================
   0 = 0

subgoal 2 is:
 S n + 0 = S n

pluszero < reflexivity.
1 subgoal

  n : nat
  IHn : n + 0 = n
  ============================
   S n + 0 = S n

0+0をplusの定義で展開してみます。
plusの定義は、

Coq < Print plus.
plus =
fix plus (n m : nat) {struct n} : nat :=
  match n with
  | 0 => m
  | S p => S (p + m)
  end
     : nat -> nat -> nat


Argument scopes are [nat_scope nat_scope]

0 + 0で、plusを展開すると、matchのうち、+の左の0のパターンによりm、このmが+の右の0になって、=の左辺が0になり、0 = 0で同値reflexivityでサブゴールが終了。

pluszero < unfold plus.
1 subgoal

  n : nat
  IHn : n + 0 = n
  ============================
   S
     ((fix plus (n0 m : nat) {struct n0} : nat :=
         match n0 with
         | 0 => m
         | S p => S (p + m)
         end) n 0) = S n

pluszero < fold plus.
1 subgoal

  n : nat
  IHn : n + 0 = n
  ============================
   S (n + 0) = S n

前のゴール同様に、左辺のplus (S n) 0 をplusの定義で展開すると、S側のS (p + m)にマッチして展開されるが、unfldでp+m中の再帰的なplusまでも展開してしまう。そこでそのplusの展開をfold plusに書き戻すことで、S (n + 0)となります。

  • unfold f: fの定義で展開し、パターン簡約(beta iota reduction)する
  • fold f: fの定義をfに置き換える

( http://coq.inria.fr/doc/Reference-Manual010.html#htoc212 より)

pluszero < rewrite IHn.
1 subgoal

  n : nat
  IHn : n + 0 = n
  ============================
   S n = S n

pluszero < reflexivity.
Proof completed.

IHnの等式の左辺側で置き換え、同値で証明終了。

pluszero < Qed.
intros.
induction n.
 unfold plus in |- *.
   reflexivity.
unfold plus in |- *.
  fold plus in |- *.
  rewrite IHn in |- *.
  reflexivity.
pluszero is defined

一応、どんなコードが生成されるか。

Coq < Print pluszero.
pluszero =
fun n : nat =>
nat_ind (fun n0 : nat => n0 + 0 = n0) (refl_equal 0)
  (fun (n0 : nat) (IHn : n0 + 0 = n0) =>
   eq_ind_r (fun n1 : nat => S n1 = S n0) (refl_equal (S n0)) IHn) n
     : forall n : nat, n + 0 = n


Argument scope is [nat_scope]

わけわかりませんが、_indや_equalがinduction,reflexivityにより生成されるものであることから、なんとなくあのへんがunfoldやfoldになってそうという気はしそうです。


実のところ、この証明はautoで可能。その場合は、

Coq < Lemma bar: forall n:nat, plus n 0 = n.
1 subgoal

  ============================
   forall n : nat, n + 0 = n

bar < intros.
1 subgoal

  n : nat
  ============================
   n + 0 = n

bar < auto.
Proof completed.

bar < Qed.
intros.
auto.
bar is defined

そのコードは。

Coq < Print bar.
bar = fun n : nat => sym_eq (plus_n_O n)
     : forall n : nat, n + 0 = n


Argument scope is [nat_scope]

同様のplus_n_0: n=n+0がすでにnatで定義されていました。