我创建了这个示例类型来演示我遇到的问题:
Inductive foo : nat -> Prop :=
| foo_1 : forall n, foo n
| foo_2 : forall n, foo n.
现在明确foo_1 0 <> foo_2 0
,但我无法证明这一点:
Lemma bar : foo_1 0 <> foo_2 0.
Proof. unfold not. intros H. discriminate H.
这会返回错误
不是可辨别的平等。
inversion H
根本不会改变上下文。奇怪的是,如果我将foo
从Prop
更改为Type
,那么证明就会通过,但我不能在我的实际代码中执行此操作,因为它会在其他地方引起问题。
我如何才能获得此证明?为什么这首先出现问题?
答案 0 :(得分:4)
Coq背后的逻辑与“证明不相关”的公理相容,该公理表明给定Prop
的任何两个证明是相等的。因此,无法证明你所制定的陈述。
如果您希望能够区分两个构造函数,则需要使foo
成为归纳Type
而不是Prop
。然后bar
被接受为有效证据。
Inductive foo : nat -> Type :=
| foo_1 : forall n, foo n
| foo_2 : forall n, foo n.
Lemma bar : foo_1 0 <> foo_2 0.
Proof. unfold not. intros H. discriminate H. Qed.
答案 1 :(得分:3)
简短回答:你不能。
让我们举一个更简单的例子,我们也未能证明类似的事情:
Inductive baz : Prop :=
| baz1 : baz
| baz2 : baz.
Goal baz1 <> baz2.
intro H.
Fail discriminate H.
Abort.
上述操作失败,并显示以下错误消息:
错误:不是可辨别的平等。
现在,让我们试着找出discriminate
失败的原因。
首先,让我们绕道而行,证明一个非常简单的陈述:
Goal false <> true.
intro prf; discriminate.
Qed.
我们也可以通过直接提供其证明条件来证明上述目标,而不是使用策略构建它:
Goal false <> true.
exact (fun prf : false = true =>
eq_ind false (fun e : bool => if e then False else True) I true prf).
Qed.
以上是discriminate
策略构建的简化版本。
让我们相应地用false
,true
,bool
替换证明字词中的baz1
,baz2
和baz
,看看会发生什么:
Goal baz1 <> baz2.
Fail exact (fun prf : baz1 = baz2 =>
eq_ind baz1 (fun e : baz => if e then False else True) I baz2 prf).
Abort.
上述内容因以下原因失败:
命令确实失败,并带有消息:
归纳类型e
中baz
的错误消除:
返回类型的排序为Type
,而它应为Prop
消除排序Prop
的归纳对象 排序Type
中的谓词不允许 因为证据可以被删除只是为了建立证明。
错误的原因是这种抽象:
Fail Check (fun e : baz => if e then False else True).
以上产生相同的错误消息。
而且很容易理解为什么。抽象的类型是baz -> Prop
,什么是baz -> Prop
的类型?
Check baz -> Prop. (* baz -> Prop : Type *)
从命题到命题的证据的地图位于Type
中的Prop
,而不是!否则会导致宇宙不一致。
我们的结论是没有办法证明不平等,因为没有办法突破Prop
来做到这一点 - 你不能只使用重写(baz1 = baz2
)来建立False
的证明。
另一个论点(我认为它已经由@gallais提出):如果有可能使用一些聪明的技巧并使证据保持在Prop
内,那么proof irrelevance公理将是不一致的与Coq的逻辑:
Variable contra : baz1 <> baz2.
Axiom proof_irrelevance : forall (P:Prop) (p1 p2:P), p1 = p2.
Check contra (proof_irrelevance _ baz1 baz2). (* False *)
但是,已知它是一致的,请参阅Coq's FAQ。