![](/img/trans.png)
[英]How to prove “~(nat = False)”, “~(nat = bool)” and “~(nat = True)” in coq
[英]What does `true = false` mean in Coq?
[我不确定这是否适合堆栈溢出,但这里还有许多其他 Coq 问题,所以也许有人可以提供帮助。]
我正在通过http://www.cis.upenn.edu/~bcpierce/sf/Basics.html#lab28 (就在 Case 介绍的下方)中完成以下工作。 请注意,我在这方面是一个完整的初学者,并且正在家里工作 - 我不是学生。
Theorem andb_true_elim1 : forall b c : bool,
andb b c = true -> b = true.
Proof.
intros b c H.
destruct b.
Case "b = true".
reflexivity.
Case "b = false".
rewrite <- H. reflexivity.
Qed.
我正在研究重写的作用:
Case := "b = false" : String.string
c : bool
H : andb false c = true
============================
false = true
然后rewrite <- H.
被应用:
Case := "b = false" : String.string
c : bool
H : andb false c = true
============================
false = andb false c
很明显证明将如何成功。
我可以看到如何以机械方式操纵符号来获得证明。 没关系。 但我对“意义”感到不安。 特别是,我怎么能在证明中间有false = true
?
似乎我正在提出某种矛盾的论点,但我不确定是什么。 我觉得我一直在盲目地遵守规则,不知何故到了我打字胡说八道的地步。
我在上面做什么?
我希望这个问题很清楚。
通常,当您在定理证明器中进行案例分析时,很多案例归结为“不可能发生”。 例如,如果您要证明有关整数的一些事实,您可能需要对整数i
是正数、零还是负数进行案例分析。 但是,在您的上下文中,或者您的目标的某些部分,可能还有其他假设与其中一种情况相矛盾。 例如,您可能从之前的断言中知道, i
永远不会是否定的。
然而,Coq 并不那么聪明。 因此,您仍然必须通过实际证明这两个相互矛盾的假设可以粘合在一起成为荒谬证明,从而证明您的定理的机制。
把它想象成一个计算机程序:
switch (k) {
case X:
/* do stuff */
break;
case Y:
/* do other stuff */
break;
default:
assert(false, "can't ever happen");
}
false = true
目标是“永远不会发生”。 但是你不能只是在 Coq 中断言你的出路。 你实际上必须写下一个证明术语。
所以上面,你必须证明荒谬的目标false = true
。 您唯一需要处理的是假设H: andb false c = true
andb H: andb false c = true
。 稍加思考就会告诉你,这实际上是一个荒谬的假设(因为对于任何y
, andb false y
减少为 false,因此不可能为真)。 所以你用唯一可以使用的东西(即H
) false = andb false c
目标,你的新目标是false = andb false c
。
所以你应用一个荒谬的假设来试图实现一个荒谬的目标。 瞧,你最终得到了一些你可以通过反身性来展示的东西。 Qed。
更新正式,这是发生了什么。
回想一下 Coq 中的每个归纳定义都带有一个归纳原则。 以下是等式和False
命题的归纳原则的类型(与bool
类型的术语false
相对):
Check eq_ind.
eq_ind
: forall (A : Type) (x : A) (P : A -> Prop),
P x -> forall y : A, x = y -> P y
Check False_ind.
False_ind
: forall P : Prop, False -> P
False
归纳原理说,如果你给我一个False
的证明,我可以给你任何命题P
的证明。
eq
的归纳原理比较复杂。 让我们考虑它仅限于bool
。 并专门为false
。 它说:
Check eq_ind false.
eq_ind false
: forall P : bool -> Prop, P false -> forall y : bool, false = y -> P y
因此,如果您从某个依赖于布尔值b
命题P(b)
开始,并且您有P(false)
的证明,那么对于任何其他等于false
布尔值y
,您就有了P(y)
的证明.
这听起来并不特别令人兴奋,但我们可以将它应用于我们想要的任何命题P
我们想要一个特别讨厌的。
Check eq_ind false (fun b : bool => if b then False else True).
eq_ind false (fun b : bool => if b then False else True)
: (fun b : bool => if b then False else True) false ->
forall y : bool,
false = y -> (fun b : bool => if b then False else True) y
稍微简化一下,这就是True -> forall y : bool, false = y -> (if y then False else True)
。
所以这需要一个True
的证明,然后是一些我们可以选择的布尔值y
。 所以让我们这样做。
Check eq_ind false (fun b : bool => if b then False else True) I true.
eq_ind false (fun b : bool => if b then False else True) I true
: false = true -> (fun b : bool => if b then False else True) true
我们在这里: false = true -> False
。
结合我们对False
归纳原理的了解,我们有:如果你给我一个false = true
证明,我可以证明任何命题。
所以回到andb_true_elim1
。 我们有一个假设H
是false = true
。 我们想证明某种目标。 正如我上面所展示的,存在一个证明项,可以将false = true
证明转换为您想要的任何证明。 所以特别是H
是false = true
的证明,所以你现在可以证明你想要的任何目标。
策略基本上是构建证明项的机器。
true = false
是一个等于两个不同布尔值的语句。 由于这些值不同,此陈述显然无法证明(在空上下文中)。
考虑你的证明:你到达了目标为false = true
的阶段,很明显你无法证明它......但问题是你的上下文(假设)也是矛盾的。 例如,当您进行案例分析并且其中一个案例与您的其他假设相矛盾时,经常会发生这种情况。
我意识到这很旧,但我想澄清 Lambdageek 答案背后的一些直觉(以防有人发现这一点)
我注意到关键点似乎是我们定义了一个函数F:bool->Prop
在每个点都有不同的值(即true => True
和false => False
)。 然而,可以很容易地从等式的归纳原理eq_ind
直观的想法(这实际上是定义等式的“莱布尼茨”方式)表明
forall P:bool -> Prop, forall x,y:bool, (x = y) -> (P x) -> (P y),
但这意味着从true=false
和I:True
,我们可以得出结论False
。
我们在这里使用的另一个基本属性是定义F
的能力,它由 bool 的递归原则bool_rect
:
forall P:bool -> Type, P true -> P false -> (forall b:bool, P b)
通过选择P := (fun b:bool => Prop)
,我们得到
(bool_rect P) : Prop -> Prop -> (bool -> Prop),
我们输入True
和False
来得到我们的函数F
。
如果我们把这一切放在一起,我们会得到
(eq_ind true (bool_rect (fun b => Prop) True False) I false) : true = false -> False
还值得指出的是,Coq 将eq_ind
或bool_rect
等归纳/递归原则作为定义身份和布尔类型的公理。
证明这一点的正常人类方法是说,由于在这种情况下假设不匹配,因此我们不需要证明续集。 在 Coq 中,有一种表达方式。 这是通过一种名为inversion
的策略。
下面是一个例子:
Theorem absurd_implies_absurd :
true = false -> 1 = 2.
Proof.
intros H.
inversion H.
Qed.
第一步让H
成为假设true = false
,因此要证明的目标是1 = 2
。
inversion H
步将自动证明目标! 正是我们想要的,魔法!
为了理解这种魔法,我们转向了inversion
意味着什么的文档。
对于初学者(像我一样),反演的官方文档简洁而晦涩难懂,这里有一个更好的解释。 在页面上搜索关键词倒置,你会发现这个:
如果c
和d
是不同的构造函数,则假设H
是矛盾的。 也就是说,错误的假设已经进入上下文,这意味着任何目标都是可证明的! 在这种情况下,反转 H 将当前目标标记为已完成并将其从目标堆栈中弹出。
这正是我们想要的。 唯一的问题是这超出了本书的计划。 当然,将true
重写为false
会起作用。 问题不在于它不起作用,问题在于它不是我们想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.