使用sig类型定义:
Inductive A: Set := mkA : nat-> A.
Function getId (a: A) : nat := match a with mkA n => n end.
Function filter (a: A) : bool := if (beq_nat (getId a) 0) then true else false.
Coercion is_true : bool >-> Sortclass.
Definition subsetA : Set := { a : A | filter a }.
我试图证明它的投射是单射的:
Lemma projection_injective :
forall t1 t2: subsetA, proj1_sig t1 = proj1_sig t2 -> t1 = t2.
Proof.
destruct t1.
destruct t2.
simpl.
intros.
rewrite -> H. (* <- stuck here *)
Abort.
此时,Coq知道:
x : A
i : is_true (filter x)
x0 : A
i0 : is_true (filter x0)
H : x = x0
我尝试了一些改写没有成功。例如,为什么我不能重写i
和H
来给Coq一个i0
?请问这里我想念的是什么?感谢。
答案 0 :(得分:2)
当你遇到困难时,你的目标大致如下:
exist x i = exist x0 i0
如果您输入的重写成功,您将获得以下目标:
exist x0 i = exist x0 i0
在这里,你可以看到为什么Coq抱怨:重写可能会产生一个错误的术语。问题是子项exist x0 i
使用i
作为filter x0
类型的术语,当它确实具有类型filter x
时。为了让Coq相信这不是问题,你需要在重写之前按摩你的目标:
Lemma projection_injective :
forall t1 t2: subsetA, proj1_sig t1 = proj1_sig t2 -> t1 = t2.
Proof.
destruct t1.
destruct t2.
simpl.
intros.
revert i. (* <- this is new *)
rewrite -> H. (* and now the tactic succeeds *)
intros i.
Abort.
或者,您可以使用subst
策略,该策略尝试删除上下文中的所有冗余变量。以下是上述脚本的更紧凑版本:
Lemma projection_injective :
forall t1 t2: subsetA, proj1_sig t1 = proj1_sig t2 -> t1 = t2.
Proof.
intros [x1 i1] [x2 i2]; simpl; intros e.
subst.
Abort.
之后您可能会遇到另一个问题:显示filter x0
类型的任何两个术语都相同。一般来说,你需要证明不相关的公理才能表明这一点;但是,由于filter
被定义为具有可判定等式的类型的两个项之间的相等,因此您可以将此属性证明为一个定理(Coq standard library已经为您做过)。
作为旁注,mathcomp库已经有一个generic lemma包含您的财产,名为val_inj
。只是举个例子,这是人们可以使用它的方式:
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype.
Inductive A: Set := mkA : nat-> A.
Function getId (a: A) : nat := match a with mkA n => n end.
Function filter (a: A) : bool := if (Nat.eqb (getId a) 0) then true else false.
Definition subsetA : Set := { a : A | filter a }.
Lemma projection_injective :
forall t1 t2: subsetA, proj1_sig t1 = proj1_sig t2 -> t1 = t2.
Proof.
intros t1 t2.
apply val_inj.
Qed.