我一直在努力解决这个问题。我有一个归纳型:
Definition char := nat.
Definition string := list char.
Inductive Exp : Set :=
| Lit : char -> Exp
| And : Exp -> Exp -> Exp
| Or : Exp -> Exp -> Exp
| Many: Exp -> Exp
我从中定义了一系列类型:
Inductive Language : Exp -> Set :=
| LangLit : forall c:char, Language (Lit c)
| LangAnd : forall r1 r2: Exp, Language(r1) -> Language(r2) -> Language(And r1 r2)
| LangOrLeft : forall r1 r2: Exp, Language(r1) -> Language(Or r1 r2)
| LangOrRight : forall r1 r2: Exp, Language(r2) -> Language(Or r1 r2)
| LangEmpty : forall r: Exp, Language (Many r)
| LangMany : forall r: Exp, Language (Many r) -> Language r -> Language (Many r).
理性的是,给定正则表达式r:Exp
我试图将与r
相关联的语言表示为类型Language r
,并且我使用单个归纳定义来表达
我想证明:
Lemma L1 : forall (c:char)(x:Language (Lit c)),
x = LangLit c.
(换句话说,类型Language (Lit c)
只有一个元素,即正则表达式'c'
的语言由单个字符串"c"
组成。当然我需要定义某些语义将Language r
的元素转换为string
)
现在这个问题的具体细节并不重要,只是用来激发我的问题:让我们使用nat
而不是Exp
让我们定义代表列表的类型List n
长度为n
:
Parameter A:Set.
Inductive List : nat -> Set :=
| ListNil : List 0
| ListCons : forall (n:nat), A -> List n -> List (S n).
我再次使用一个归纳定义来定义一类List n
。
我想证明:
Lemma L2: forall (x: List 0),
x = ListNil.
(换句话说,类型List 0
只有一个元素)。
我对这个想法已经用完了。
通常在尝试使用归纳类型(或谓词)证明(否定)结果时,我会使用elim
策略(确保所有相关假设都在我的目标(generalize
)内并且只有变量出现在类型构造函数中)。但elim
在这种情况下并不好。
答案 0 :(得分:5)
如果您愿意接受的不仅仅是Coq的基本逻辑,您可以使用dependent destruction
库中提供的Program
策略(我已经冒昧地重述了您的上一个标准库向量的例子:
Require Coq.Vectors.Vector.
Require Import Program.
Lemma l0 A (v : Vector.t A 0) : v = @Vector.nil A.
Proof.
now dependent destruction v.
Qed.
如果你检查这个词,你会发现这个策略依赖于JMeq_eq
公理来得到证据:
Print Assumptions l0.
Axioms:
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y
幸运的是,通过对上一个引理的陈述做一个小改动,可以证明l0
而不必求助于Coq基本逻辑之外的特征。
Lemma l0_gen A n (v : Vector.t A n) :
match n return Vector.t A n -> Prop with
| 0 => fun v => v = @Vector.nil A
| _ => fun _ => True
end v.
Proof.
now destruct v.
Qed.
Lemma l0' A (v : Vector.t A 0) : v = @Vector.nil A.
Proof.
exact (l0_gen A 0 v).
Qed.
我们可以看到这个新证据不需要任何额外的公理:
Print Assumptions l0'.
Closed under the global context
这里发生了什么?粗略地说,问题是在Coq中我们不能对索引具有特定形状的依赖类型(例如0,在您的情况下)直接执行案例分析。相反,我们必须证明一个更普遍的陈述,其中有问题的指数被变量所取代。这正是l0_gen
引理正在做的事情。注意我们如何使n
上的匹配返回一个在v
上抽象的函数。这是所谓的"convoy pattern"的另一个例子。我们写过
match n with
| 0 => v = @Vector.nil A
| _ => True
end.
Coq会将v
分支中的0
视为类型Vector.t A n
,从而使该分支生病。
提出这样的概括是在Coq中进行依赖类型编程的一大难点。其他系统,例如Agda,可以用更少的努力编写这种代码,但最近才shown这可以在不依赖Coq希望避免的额外公理的情况下完成{{3}}。基本理论。我们只能希望在将来的版本中简化这一点。