我能告诉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.