我试图证明一个微不足道的引理,这是我在另一个角度发现自己的情况的再创造。
Lemma Sn_neq_n: forall n, S n <> n.
证据看起来很简单:
Proof. unfold not. intros.
现在我的目标状态显示:
n : nat
H : S n = n
===================
False
很明显S n
无法与n
统一,所以我应该能够反驳这个假设:
inversion H.
但是我的状态现在显示:
,而不是解决目标n : nat
H : S n = n
H0 : S n = n
===================
False
咦?我现在只是在无限循环中。我可以inversion H0
我只得到H1
等等。
我能够通过归纳证明这个引理:
unfold not. intros. induction n.
Case "n = 0". inversion H.
Case "n > 0". inversion H. apply IHn. apply H1.
但这有点愚蠢,因为可以想象的是统一算法,它允许反思性平等首先有意义,不应该能够S n
与n
统一。
这里发生了什么?
答案 0 :(得分:4)
要了解为什么inversion
无法单独解决这一目标,我们需要更详细地了解它的作用。
当你颠倒(共)归纳类型的假设时,粗略地说,Coq所做的就是尽可能多地使用模式匹配提取信息(记住Coq策略是总是在引擎盖下制作证明条款)。因此,当通过反演证明1 <> 0
时,Coq将产生一个如下所示的术语:
Definition one_neq_zero (p : 1 = 0) : False :=
match p in _ = n return match n with
| 0 => False
| _ => True
end
with
| eq_refl => I (* "I" is the only constructor of the True proposition *)
end.
return
语句中的match
注释对于此工作至关重要。这里发生的事情基本上如下:
p
才能使用它。n
,,即使我们知道该元素实际上是0 。这只是因为模式匹配在Coq。False
(即n = 0
),但是说我们将在其他分支上返回其他内容。match
进行类型检查,每个分支必须返回return
子句中出现的类型,但在替换变量的实际值之后受in
条款约束。eq_refl
。在这里,我们知道n = 1
。在我们的返回类型中用1代替n
,我们获得了True
,因此我们必须返回True
类型的内容,我们这样做。p
的右侧为0,Coq了解整个匹配的类型为False
,因此整个定义类型检查。最后一步只能起作用,因为0是构造函数,因此Coq能够简化返回类型的匹配,以实现我们正在返回正确的东西。 此在尝试反转S n = n
时失败:由于n
是变量,因此无法简化整个匹配。
我们可以尝试翻转相等并反转n = S n
,以便Coq可以稍微简化返回类型。不幸的是,由于类似的原因,这也不起作用。例如,如果您尝试使用in _ = m return match m with 0 => True | _ => False end
对匹配进行注释,则在eq_refl
内我们将不得不返回match n with 0 => True | _ => False end
类型的内容,而我们无法返回。
最后我要提一下,Coq中的统一算法不能像你提到的那样“消极地”使用,因为理论只定义了可证明的东西,而不是可辩驳。特别是,当我们证明一个否定的命题,如S n <> n
时,类型检查器总是测试某些统一问题是否有解决方案,而不是测试他们是否有 no 解决方案。例如,假设n = m
是一件非常好的事情,并且不会导致任何矛盾,即使n
和m
不是统一的。另请注意,如果nat
被声明为 co-inductive 类型,则S n = n
不是一个矛盾的假设,而且两个就是在这种情况下我们无法在n
上进行归纳。