我能告诉Coq从n到n+;2.

我能告诉Coq从n到n+;2.,coq,induction,Coq,Induction,我试着看看是否有可能从根本不涉及奇数的情况下证明evenb n=true存在k,n=double k。我尝试了以下方法: Theorem evenb_double_k : forall n, evenb n = true -> exists k, n = double k. Proof. intros n H. induction n as [|n' IHn']. - exists 0. reflexivity. - (* stuck *) 但显然归纳法一次只能工作一个自

我试着看看是否有可能从根本不涉及奇数的情况下证明
evenb n=true存在k,n=double k
。我尝试了以下方法:

Theorem evenb_double_k : forall n,
  evenb n = true -> exists k, n = double k.
Proof.
  intros n H. induction n as [|n' IHn'].
  - exists 0. reflexivity.
  - (* stuck *)
但显然归纳法一次只能工作一个自然数,并且
存在k:nat,sn'=双k
显然是不可证明的

n' : nat
H : evenb (S n') = true
IHn' : evenb n' = true -> exists k : nat, n' = double k
______________________________________(1/1)
exists k : nat, S n' = double k

有没有办法让感应从n变为n+2?

是的,绝对有!让我们使用来自的归纳原理

现在我们可以使用这样的新原理(我将非标准函数与stdlib对应的函数进行了切换,以便一切都可以编译):


有一种策略叫做
fix
。我将尝试从较高的层次解释正在发生的事情,因为我认为这是一个很酷的黑客行为,但请注意,
fix
是一把双刃剑,通常不建议使用:它取决于Coq的真正低层次细节,这使得证明非常脆弱,当它们破裂时,错误消息很难理解

fix foo i
,其中
foo
是一个新变量,
i
是一个整数,是一种策略,适用于至少有
i
参数的目标(例如,
forall n,evenb n=true->…
有两个参数:
n
evenb n=true
的证明),而假设你试图证明的目标,将新假设命名为
foo
。(是的,你读对了。)

当然,这里有一个陷阱:这个假设必须应用于
n
的适当子项(这是目标的第一个参数,这就是
fix self 1
的数字参数的意思,我们说第一个参数是递减参数)。
n
的适当子项是什么?该值只能通过至少一次销毁
n
来获得

请注意,如果您仍然决定直接应用假设
self
n
本身不是合适的子项),Coq不会立即抱怨。Coq仅检查
Qed
上的“子项”要求。编辑:您也可以随时使用命令
Guarded
来检查这一点

  apply self. (* seems fine, all goals done. *)
Qed. (* ERROR! *)
您可以大致将
fix
想象为强归纳的一种形式,其中归纳假设(
self
)适用于所有小于当前项的项,而不仅仅是直接前置项。然而,这种“子项”关系实际上并不出现在
self
语句中。(正是这种特性使得
fix
成为一种低级的、危险的战术。)

fix
之后,您通常希望
destruct
递减参数。这就是
fix
允许您的证明遵循
evenb
的结构的地方。下面,我们在
S
案例中立即再次销毁。因此我们得到了三种情况:
n=O
n=So
n=S(sn')
对于一些
n':nat

Proof.
  intros P HO HSS.
  fix self 1.
  intros n.
  destruct n as [| [| n']].
  - intro; apply HO.
  - discriminate.
  - intros H. apply HSS.
    + apply H.
    + apply self.
      apply H.
Qed.
第一种情况很简单,第二种情况是真空的,第三种情况是在
n'
处需要“归纳假设”
self

Proof.
  fix self 1.
  intros n.
  destruct n as [| [| n']].
  - exists 0; reflexivity.
  - discriminate.
  - simpl. intro H.
    apply self in H.
    destruct H as [k Hk].
    exists (S k).
    rewrite Hk; reflexivity.
Qed.
那里的一些推理是相当通用的,它甚至可以被拉到一个自定义归纳原则中,用于
nat
s,这是另一个
定理

Theorem even_ind :
  forall (P : nat -> Prop),
    P O ->
    (forall n, evenb n = true -> P n -> P (S (S n))) ->
    forall n, evenb n = true -> P n.
将其与
nat
的标准归纳原理进行比较,这实际上也是一个定理,名为
nat\u ind
。这就是
诱导
策略在发动机罩下的用途

About nat_ind.

(* nat_ind :
     forall P : nat -> Prop,
       P 0 ->
       (forall n : nat, P n -> P (S n)) ->
       forall n : nat, P n
 *)
nat\u ind
中的归纳步骤从
n
sn
,而
偶数ind
的归纳步骤从
n
sn
,并且有一个额外的假设说我们的数字是偶数

even\u ind
的证明遵循与
evenb\u double\k
类似的结构,尽管它更抽象,因为它概括了
nat
上的所有谓词
p

Proof.
  intros P HO HSS.
  fix self 1.
  intros n.
  destruct n as [| [| n']].
  - intro; apply HO.
  - discriminate.
  - intros H. apply HSS.
    + apply H.
    + apply self.
      apply H.
Qed.
这里的另一种方法是根本不使用
fix
(因为应该避免),而是将
归纳法
作为一种原语来证明替代的
甚至ind
原则。对于
nat
,这很好,但对于某些复杂的归纳类型,默认归纳原则太弱,只有手写的
fix

最后,回到
evenb\u double\k
,我们可以使用新的归纳原则
apply even\u ind
,而不是
fix
归纳法。我们现在只得到两个有意义的情况,
O
S(sn')
,其中
n'
是偶数

Theorem evenb_double_k' : forall n,
  evenb n = true -> exists k, n = double k.
Proof.
  apply even_ind.
  - exists 0. reflexivity.
  - intros n H [k Hk].
    exists (S k).
    rewrite Hk.
    reflexivity.
Qed.

本答复中使用的定义:

Fixpoint evenb n :=
  match n with
  | S (S n') => evenb n'
  | S O => false
  | O => true
  end.

Fixpoint double k :=
  match k with
  | O => O
  | S k' => S (S (double k'))
  end.

我仍然需要时间去理解引理,但是证明非常有效。谢谢与常规归纳原则相比,我们加强了新的归纳步骤:为了证明谓词包含某个数字,您将有两个辅助假设,即谓词包含该数字的两个直接前辈。但我们必须通过更多的证明义务来为这一加强付出代价——我们有两个基本案例需要进行归纳。直观地说,您从
p0
p1
开始,生成
p2
,然后我们可以使用
p1
p2
来获得
p3
,依此类推。例如,如果一个人只有
p0
而没有
p1
,那么他不能使用该步骤获得
p2
。感谢您的详细解释。与另一个答案一样,我对Coq还不够熟悉,无法理解每一步,但我喜欢提取偶数定理的想法,而且它根本不涉及奇数。我想知道你可以在证明过程中使用
guard.
来提前验证你的证明是否满足“子项”是件好事要求。哦,是的,我完全忘记了,但那肯定非常有用!哇,真是太棒了!谢谢
Theorem evenb_double_k' : forall n,
  evenb n = true -> exists k, n = double k.
Proof.
  apply even_ind.
  - exists 0. reflexivity.
  - intros n H [k Hk].
    exists (S k).
    rewrite Hk.
    reflexivity.
Qed.
Fixpoint evenb n :=
  match n with
  | S (S n') => evenb n'
  | S O => false
  | O => true
  end.

Fixpoint double k :=
  match k with
  | O => O
  | S k' => S (S (double k'))
  end.