Coq 用有充分根据的归纳法定义阶乘

Coq 用有充分根据的归纳法定义阶乘,coq,Coq,我花了很多时间研究有充分根据的归纳法的概念,并认为是时候将其应用于一个简单的案例了。所以我想用它来定义阶乘函数,并提出: Definition fac : nat -> nat := Fix LtWellFounded (fun _ => nat) (* 'LtWellFounded' is some proof *) (fun (n:nat) => match n as n' return (forall (m:nat), m < n' -&

我花了很多时间研究有充分根据的归纳法的概念,并认为是时候将其应用于一个简单的案例了。所以我想用它来定义阶乘函数,并提出:

Definition fac : nat -> nat := Fix LtWellFounded (fun _ => nat)   (* 'LtWellFounded' is some proof *)
    (fun (n:nat) =>
        match n as n' return (forall (m:nat), m < n' -> nat) -> nat with
        | 0     => fun _ => 1
        | S m   => fun (g : forall (k:nat), k < S m -> nat) => S m *  g m (le_n (S m)) 
        end).
似乎很难。我只剩下一个目标:

1 subgoal

  ============================
  (fix Fix_F (x : nat) (a : Acc lt x) {struct a} : nat :=
     match x as n' return ((forall m : nat, m < n' -> nat) -> nat) with
     | 0 => fun _ : forall m : nat, m < 0 -> nat => 1
     | S m =>
         fun g : forall k : nat, k < S m -> nat => S m * g m (le_n (S m))
     end (fun (y : nat) (h : y < x) => Fix_F y (Acc_inv a h))) 0
    (LtWellFounded' 0) = 1

我看不出如何进一步减少它。有人能建议一条前进的路吗

不动点的应用程序只有在其递归的参数的头部有构造函数时才会减少。析构函数“0”以显示构造函数,然后这将减少到1=1。或者,更好的是,确保LtWellFounded'是透明的,它的证明应该以Defined.而不是Qed.结尾,然后整个证明就是自反性。

不动点的应用程序只有在它递归的参数的头部有一个构造函数时才会减少。析构函数“0”以显示构造函数,然后这将减少到1=1。或者,更好的是,确保LTWellBounded'是透明的,它的证明应该以Defined.而不是Qed.结尾,然后整个证明就是自反性。

您给出的一些类型实际上可以由Coq推断,因此您也可以编写 你的谎言更具可读性。使用dec不要忘记您所在的if分支,并使递归函数采用递归函数fac作为参数。它可以用较小的参数调用。通过使用refine,您可以像在Agda中一样插入孔,并在以后获得证明义务

Require Import Wf_nat PeanoNat Psatz. (* for lt_wf, =? and lia *)

Definition dec b: {b=true}+{b=false}.
  now destruct b; auto.
Defined.

Definition fac : nat -> nat.
  refine (Fix lt_wf _
   (fun n fac =>
      if dec (n =? 0)
      then 1
      else n * (fac (n - 1) _))).

  clear fac. (* otherwise proving fac_S becomes impossible *)
  destruct n; [ inversion e | lia].
Defined.

Lemma fac_S n: fac (S n) = (S n) * fac n.
  unfold fac at 1; rewrite Fix_eq; fold fac.
  now replace (S n - 1) with n by lia.
  now intros x f g H; case dec; intros; rewrite ?H. 
Defined.

Compute fac 8.
给予


您提供的某些类型实际上可以由Coq推断,因此您也可以编写 你的谎言更具可读性。使用dec不要忘记您所在的if分支,并使递归函数采用递归函数fac作为参数。它可以用较小的参数调用。通过使用refine,您可以像在Agda中一样插入孔,并在以后获得证明义务

Require Import Wf_nat PeanoNat Psatz. (* for lt_wf, =? and lia *)

Definition dec b: {b=true}+{b=false}.
  now destruct b; auto.
Defined.

Definition fac : nat -> nat.
  refine (Fix lt_wf _
   (fun n fac =>
      if dec (n =? 0)
      then 1
      else n * (fac (n - 1) _))).

  clear fac. (* otherwise proving fac_S becomes impossible *)
  destruct n; [ inversion e | lia].
Defined.

Lemma fac_S n: fac (S n) = (S n) * fac n.
  unfold fac at 1; rewrite Fix_eq; fold fac.
  now replace (S n - 1) with n by lia.
  now intros x f g H; case dec; intros; rewrite ?H. 
Defined.

Compute fac 8.
给予


FWIW,模块Wf_nat有lt_Wf:well_founded lt,它是透明的,因此使用lt_Wf而不是ltwell founded解决了这个问题。非常感谢各位,也谢谢你们的提示。。。fix point的头参数,定义vs Qed,lt_wf已经存在。Wiw,模块wf_nat有lt_wf:lt_wf,它是透明的,因此使用lt_wf而不是LTWellbounded解决了这个问题。非常感谢各位,也谢谢你们的提示。。。fix point的头参数,定义vs Qed,lt_wf已经存在,hanks v more Iarsr,这段代码看起来更可读。我会仔细研究的。非常感谢,这段代码看起来更可读。我会仔细研究的。
Compute fac 8.
     = 40320
     : nat