要了解为什么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
才能使用它。
- 为了能够在对其证明进行模式匹配时讨论该等式的右侧,我们必须在匹配中添加一个返回注释。
- 不幸的是,这个返回注解不能直接提到 0。相反,它需要为泛型
n
工作,即使我们知道该元素实际上是 0。这仅仅是因为模式匹配在 Coq 中的工作方式。
- 在 return 注释上,我们在 Coq 上玩了一个“技巧”:我们说我们将返回
False
我们真正关心的情况(即n = 0
),但说我们将在其他分支上返回其他内容。
- 要对 进行类型检查
match
,每个分支都必须返回出现在return
子句中的类型,但是在替换子句上绑定的变量的实际值in
之后。
- 在我们的例子中,等式类型只有一个构造函数,
eq_refl
。在这里,我们知道n = 1
。用1 代替n
我们的返回类型,我们得到True
,所以我们必须返回一些 type 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
,类型检查器总是测试某些统一问题是否有解决方案,而不是测试它们是否没有解决方案。例如,假设这n = m
是一件非常好的事情,并且不会导致任何矛盾,即使并且不是n
统一m
的。另请注意,如果被声明为共归纳类型,则为nat
S n = n
不是一个矛盾的假设,两者之间的区别只是在这种情况下我们无法对 进行归纳n
。