多态和归纳数据类型


10

我很好奇。我一直在OCaml中处理此数据类型:

type 'a exptree =
  | Epsilon
  | Delta of 'a exptree * 'a exptree
  | Omicron of 'a
  | Iota of 'a exptree exptree

可以使用显式类型的递归函数(最近添加的功能)进行操作。例:

let rec map : 'a 'b. ('a -> 'b) -> 'a exptree -> 'b exptree =
  fun f ->
    begin function
    | Epsilon -> Epsilon
    | Delta (t1, t2) -> Delta (map f t1, map f t2)
    | Omicron t -> Omicron (f t)
    | Iota tt -> Iota (map (map f) tt)
    end

但是我从来没有能够在Coq中定义它:

Inductive exptree a :=
  | epsilon : exptree a
  | delta : exptree a -> exptree a -> exptree a
  | omicron : a -> exptree a
  | iota : exptree (exptree a) -> exptree a
.

Coq在抱怨。它不喜欢最后一个构造函数,并说了一些我不完全理解或不同意的内容:

Error: Non strictly positive occurrence of "exptree" in "exptree (exptree a) -> exptree a".

我能理解的是,在其定义之内使用否定的归纳类型type 'a term = Constructor ('a term -> …)会被拒绝,因为它们会导致丑陋的,毫无根据的野兽,例如(无类型的)λ项。但是,这种特殊的exptree数据类型似乎足够无害:从其OCaml定义来看,其参数'a从未在负数位置使用。

似乎Coq在这里太谨慎了。那么,这种特殊的归纳数据类型真的存在问题吗?还是Coq在这里可以放宽一点?

另外,其他证明助手又如何应对这种归纳定义(自然)呢?

Answers:


9

这已经多次出现在Coq邮件列表中,但是我从来没有看到最终的答案。Coq并不像它一般的那么广泛。(Coquand,1990)和(Giménez,1998)(及其博士学位论文)中的规则较为笼统,不需要严格的积极性。但是,当您出门在外时,仅凭积极性还不够Set。此示例经过多次讨论

Inductive Big : Type := B : ((B -> Prop) -> Prop) -> Big.

对于像您这样的简单数据结构,归纳类型不会导致问题,除了使实现更加复杂之外。

F=ϵ+δF×F+ο一世d+FF

ËXpŤ[RËË一个ËXpŤ[RËË一个ËXpŤ[RËËËXpŤ[RËËËXpŤ[RËËËXpŤ[RËËËXpŤ[RËËËXpŤ[RËËËXpŤ[RËË0一个=一个ËXpŤ[RËË1个一个=ËXpŤ[RËË一个ËXpŤ[RËË2一个=ËXpŤ[RËËËXpŤ[RËË一个一个ËXpŤ[RËË0一个=一个

Inductive et : nat -> Type -> Type :=
  | alpha : forall a, a -> et 0 a                      (*injection*)
  | omicron : forall n a, et n a -> et (S n) a         (**)
  | epsilon : forall (S n) a, et (S n) a
  | delta : forall n a, et (S n) a -> et (S n) a -> et (S n) a
  | iota : forall n a, et (S (S n)) a -> et (S n) a
.

您可以继续定义值并对其进行处理。Coq通常将能够推断出指数。Set Implicit Arguments会使这些定义更漂亮。

Definition exptree := et 1.
Definition et1 : exptree nat :=
  delta _ _ (omicron _ _ (alpha _ 42)) (epsilon _ _).
Definition et2 : exptree nat := iota _ _ (omicron _ _ et1).

exptreeet 0S n一个一个

Inductive et : nat -> Type -> Type :=
  | omicron_0 : forall a, a -> et 0 a
  | omicron_S : forall n a, et n a -> et (S n) a
  | epsilon : forall n a, et n a
  | delta : forall n a, et n a -> et n a -> et n a
  | iota : forall n a, et (S n) a -> et n a
.
Definition exptree := et 0.
Definition et1 : exptree nat :=
  delta _ _ (omicron_0 _ 42) (epsilon _ _).
Definition et2 : exptree nat :=
  (iota _ _ (omicron_S _ _ et1)).

我认为这与拉尔夫·马特斯(Ralph Mattes)提出的一般性原则相同。

参考文献

蒂埃里·考昆德(Thierry Coquand)和克里斯汀·波林(Christine Paulin)。归纳定义的类型。在COLOG'88论文集,LNCS 417,1990。[ 施普林格 ] [ 谷歌 ]

爱德华多(EduardoGiménez)。类型理论中的结构递归定义。在ICALP'98:第25届自动机,语言和程序设计国际学术研讨会论文集中。施普林格出版社,1998年。 [ PDF ]


8

Ralph Matthes在Coq的“迭代功率的数据结构”(代码论文)中描述了如何模拟类似的类型。


6

Coq要做的第一件事之一就是建立与您刚刚定义的归纳类型相关联的归纳原理,并且了解基础归纳原理是一项很好的练习。

例如O : nat | S : nat -> nat会产生归纳原理P O -> (∀ n, P n -> P (S n)) -> ∀ n, P n

对应的归纳原理是iota什么?似乎没有谓语P,这将是能够谈论P tP (iota t),因为它应该谈谈exptree aexptree (exptree a)exptree (exptree (exptree a))...

另外,它们Omicron执行相同的操作,但是每次的类型都较小。您应该感觉到同时引用较小的类型和较大的类型会使事情变得混乱。(也就是说,Omicron正确的方法)

这并不是说为什么不接受该定义的确切标准,但这解释了为什么对我来说它是错误的。

exptree似乎您正在为表达式构建语法,而这种语法通常不是那么递归的。您想要一些帮助吗?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.