类型族的归纳定义

时间:2016-05-21 19:02:23

标签: coq

我一直在努力解决这个问题。我有一个归纳型:

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在这种情况下并不好。

1 个答案:

答案 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}}。基本理论。我们只能希望在将来的版本中简化这一点。