δ-reduction

δ-reduction は変数をその定義で置き換える。

まず何か定義して、

Coq < Definition hoge := fun x:nat => 2+x.
hoge is defined

cbvを実行してみる。

Coq < Eval cbv delta [hoge] in (hoge 3).
     = (fun x : nat => 2 + x) 3
     : nat

この場合は「hoge」だけを展開する。

さらに「plus」も展開してみる。

Coq < Eval cbv delta [hoge plus] in (hoge 3).
     = (fun x : nat =>
        (fix plus (n m : nat) {struct n} : nat :=
           match n with
           | 0 => m
           | S p => S (p + m)
           end) 2 x) 3
     : nat

全部の定義を展開したい場合は[]はいらない。

β-reduction

β-reduction は

(fun x:T, t) a

t{a/x}

に変換する。ここで{a/x}はtの中に含まれるxをaに置き換える操作。

Coq < Eval cbv delta [hoge] beta in (hoge 3).
     = 2 + 3
     : nat

さらにplusも展開すると

Coq < Eval cbv delta beta in (hoge 3).
     = (fix plus (n m : nat) {struct n} : nat :=
          match n with
          | 0 => m
          | S p => S (p + m)
          end) 2 3
     : nat

ι-reduction

ι-reduction は再帰的な定義を展開する。fixpointもできるだけ計算してくれる。

まず、ちっとも計算できない場合。

Coq < Eval cbv delta beta iota in plus.
     = fix plus (n m : nat) {struct n} : nat :=
         match n with
         | 0 => m
         | S p => S (p + m)
         end
     : nat -> nat -> nat

これは n が分からないので、これ以上進まない。ひとつ引数を与えると

Coq < Eval cbv delta beta iota in (plus 2).
     = fun m : nat => S (S m)
     : nat -> nat

と、完全に計算してくれる。

ζ-reduction

let で定義した変数を定義で置き換える。δと似てるがなぜか違う名前がついている。

cbv, lazy

cbv と lazy は指定した reduction ルールをできるだけ適用する tactic。
ふたつの違いは call-by-value か call-by-need のどっちを使うかどうか。

red

red はゴールの頭の変数だけを展開する。

hnf

red をひたすら適用するんだと思う。

simpl

δを一回だけ使い、βιする?

unfold qualid

指定した変数を展開する。

fold term

unfold の逆。

pattern term

βの逆。たとえば、ゴール

Q x y z

lt_wf_ind :
  forall n (P:nat -> Prop), (forall n, (forall m, m < n -> P m) -> P n) -> P n.

この定理を「n := y」として適用したいとする。ということは「P := fun n => Q x n z」ということになる。
そこで、pattern y とすると

(fun n => Q x n z) y

となって apply しやすくなる。ただこの場合は pattern しなくても、apply が正しくパターンマッチに成功するので、もっと複雑な場合で失敗したらこの方法を思い出すとよい。