说你有记录:
Lemma record_difference : forall (e1 e2 : Example),
e1 <> e2 ->
(fieldA e1 <> fieldA e2)
\/
(fieldB e1 <> fieldB e2).
我们可以证明:
Record
若然,怎么样?
一方面,它看起来是真的,因为e1
是由它们的字段绝对定义的。另一方面,我们不知道首先使e2
与Record SmallExample := {
field : nat
}.
Lemma record_dif_small : forall (e1 e2 : SmallExample),
e1 <> e2 -> field e1 <> field e2.
Proof.
unfold not; intros; apply H.
destruct e1; destruct e2; simpl in H0.
f_equal; auto.
Qed.
不同的是什么,我们应该如何决定要分离哪一方?
作为比较,请注意,如果记录中只有一个字段,我们可以证明相应的引理:
{{1}}
答案 0 :(得分:4)
另一方面,在不知道首先使
e1
与e2
不同的是什么的情况下,我们应该如何决定要分析哪一方?
这正是重点:我们需要弄清楚是什么让两种记录都不同。我们可以通过测试fieldA e1 = fieldA e2
。
Require Import Coq.Arith.PeanoNat.
Record Example := {
fieldA : nat;
fieldB : nat
}.
Lemma record_difference : forall (e1 e2 : Example),
e1 <> e2 ->
(fieldA e1 <> fieldA e2)
\/
(fieldB e1 <> fieldB e2).
Proof.
intros [n1 m1] [n2 m2] He1e2; simpl.
destruct (Nat.eq_dec n1 n2) as [en|nen]; try now left.
right. intros em. congruence.
Qed.
这里,Nat.eq_dec
是标准库中的一个函数,它允许我们检查两个自然数是否相等:
Nat.eq_dec : forall n m, {n = m} + {n <> m}.
{P} + {~ P}
符号表示一种特殊的布尔值,可以在破坏时为您提供P
或~ P
的证明,具体取决于它所在的一侧。
值得通过这个证据来看看发生了什么。例如,在证明的第三行,执行intros em
会导致以下目标。
n1, m1, n2, m2 : nat
He1e2 : {| fieldA := n1; fieldB := m1 |} <> {| fieldA := n2; fieldB := m2 |}
en : n1 = n2
em : m1 = m2
============================
False
如果en
和em
成立,则两条记录必须相等,与He1e2
相矛盾。 congruence
策略只是指示Coq试图自己解决这个问题。
有趣的是,如果没有可判定的平等,我们可以获得多远。以下类似的陈述可以简单地证明:
forall (A B : Type) (p1 p2 : A * B),
p1 = p2 <-> fst p1 = fst p2 /\ snd p1 = snd p2.
通过对立,我们得到了
forall (A B : Type) (p1 p2 : A * B),
p1 <> p2 <-> ~ (fst p1 = fst p2 /\ snd p1 = snd p2).
在这里,我们在没有可判定性假设的情况下陷入困境。 De Morgan的法律允许我们将右侧转换为~ P \/ ~ Q
形式的陈述;然而,他们的证据对可判定性有吸引力,这在Coq的建设性逻辑中通常是不可用的。