fixタクティック

fixタクティックについて。
ふつう、Coqの証明モードで構造帰納法を回したい場合は inductionタクティックを使いますが、 fix は、帰納法のためのよりプリミティブなタクティックのようです(項の場合分けをやらない).

This tactic is a primitive tactic to start a proof by induction. In general, it is easier to rely on higher-level induction tactics such as the ones described in Section 8.7.

In the syntax of the tactic, the identifier ident is the name given to the induction hypothesis. The natural number num tells on which premise of the current goal the induction acts, starting from 1 and counting both dependent and non dependent products. Especially, the current lemma must be composed of at least num products.

...

ちょっとこの説明はわかりづらいですが, 要するに "fix 仮定の名前 引数の位置." という風に書きます.例えば,

  ============================
   forall (x : T1) (y : T2), P x y

というゴールがあるとき,

fact < fix IH 1.

とやれば x の構造に関する帰納法になります.ここで IHが帰納法の仮定になります.また,

fact < fix IH 2.

とやれば y の構造に関する帰納法になります.
「どの引数について帰納法を回すか」を考えるのをサボりたい場合は refine (fix fact x y := _). とかやれば,いけるかもしれない.
どの場合でも、ゴールは

  IH : forall (x : T1) (y : T2), P x y
  ============================
   forall (x : T1) (y : T2), P x y

になります. IHを使う場合は、構造的により小さい引数を第1 (もしくは2) 引数に与えます.

使ってみる

関数 fact : nat -> nat と lt : nat -> nat -> bool を わざわざ証明モードで定義して,その途中で fixタクティックを使ってみます.
ふつう関数はGallinaで定義するので特に意味はありませんが、良い例題がうかばなかったので…

Coq < Definition fact : nat -> nat.
1 subgoal
  
  ============================
   nat -> nat

fact < fix fact 1.
1 subgoal
  
  fact : nat -> nat
  ============================
   nat -> nat

fact < intro x.
1 subgoal
  
  fact : nat -> nat
  x : nat
  ============================
   nat

fact < case x.
2 subgoals
  
  fact : nat -> nat
  x : nat
  ============================
   nat

subgoal 2 is:
 nat -> nat

fact < apply (S O). (* x=O のとき 1 *)
1 subgoal
  
  fact : nat -> nat
  x : nat
  ============================
   nat -> nat

fact < intro y.
1 subgoal
  
  fact : nat -> nat
  x : nat
  y : nat
  ============================
   nat

fact < apply (x * fact y). (* x=y+1 のとき x * fact y *)
Proof completed.

fact < Qed.
fix fact 1.
intro x.
case x.
 apply 1.
 
 intro y.
 apply (x * fact y).
 
fact is defined

ちゃんと定義できていると思います(カリーハワード的に考えて).
一応チェック.

Coq < Print fact. 
fact = 
fix fact (x : nat) : nat := match x with
                            | 0 => 1
                            | S y => x * fact y
                            end
     : nat -> nat

Argument scope is [nat_scope]

Coq < 

次は < .こんどは2番目の引数について回してみましょう.ここで定義しているのはbool型を返す関数で,Prop型をもつ述語とは違うので注意.紛らわしくてスイマセン.

Coq < Definition lt : nat -> nat -> bool.
1 subgoal
  
  ============================
   nat -> nat -> bool

lt < fix lt 2.
1 subgoal
  
  lt : nat -> nat -> bool
  ============================
   nat -> nat -> bool

lt < intros x y.
1 subgoal
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  ============================
   bool

lt < case y. (* yについて場合分け *)
2 subgoals
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  ============================
   bool

subgoal 2 is:
 nat -> bool

lt < apply false. (* y=0のときfalse *)
1 subgoal
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  ============================
   nat -> bool

lt < intro y1. (* y=y1+1のとき *)
1 subgoal
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  y1 : nat
  ============================
   bool

lt < case x. (* xについて場合分け *)
2 subgoals
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  y1 : nat
  ============================
   bool

subgoal 2 is:
 nat -> bool

lt < apply true. (* x=0のとき true *)
1 subgoal
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  y1 : nat
  ============================
   nat -> bool

lt < intro x1. (* x=x1+1 のとき *)
1 subgoal
  
  lt : nat -> nat -> bool
  x : nat
  y : nat
  y1 : nat
  x1 : nat
  ============================
   bool

lt < apply (lt x1 y1). (* 帰納法の仮定を使う,というか再帰 *)
Proof completed.

lt < Qed.
fix lt 2.
intros x y.
case y.
 apply false.
 
 intro y1.
 case x.
  apply true.
  
  intro x1.
  apply (lt x1 y1).
  
lt is defined

Coq < Print lt.
lt = 
fix lt (x y : nat) : bool :=
  match y with
  | 0 => false
  | S y1 => match x with
            | 0 => true
            | S x1 => lt x1 y1
            end
  end
     : nat -> nat -> bool

Argument scopes are [nat_scope nat_scope]

Coq < 

証明モードで作った証明が,カリーハワード同型で対応する Gallinaのプログラムになっています.大丈夫っぽいです.