具有嵌套组件的归纳类型的递归定义


21

考虑归纳类型,它在嵌套但严格为正的位置中具有一些递归出现。例如,具有节点的有限分支的树使用通用列表数据结构来存储子级。

Inductive LTree : Set := Node : list LTree -> LTree.

通过对树和树列表进行递归来定义这些树的递归函数的幼稚方法不起作用。这是带有size计算节点数的函数的示例。

Fixpoint size (t : LTree) : nat := match t with Node l => 1 + (size_l l) end
with size_l (l : list LTree) : nat := match l with
    | nil => 0
    | cons h r => size h + size_l r
  end.

该定义格式错误(错误消息摘录):

Error:
Recursive definition of size_l is ill-formed.
Recursive call to size has principal argument equal to
"h" instead of "r".

为什么定义r显然是错误的,即使它是的一个子术语l?有没有办法在这样的数据结构上定义递归函数?


如果您不熟练使用Coq语法:LTree是与以下语法相对应的归纳类型。

大号Ť[RËË:: =|一世sŤ大号Ť[RËË

我们尝试size通过对树和列表的归纳来定义功能。在OCaml中,将是:

type t = Node of t list
let rec size = function Node l -> 1 + size_l l
and size_l = function [] -> 0
                    | h::r -> size h + size_l r


您可以在少一些Coqy和更多数学的情况下添加等效的函数定义吗?我在理解语法时遇到了麻烦。
拉斐尔

1
我尝试过的@Raphael,现在好了吗?老实说,这个问题是Coq特有的。
吉尔(Gilles)'所以

Answers:


14

什么有效

如果将固定点的定义嵌套在树上固定点的定义内的列表上,则结果类型正确。当您以归纳类型嵌套递归时,即当递归通过类似的构造函数时,这是一个通用原则list

Fixpoint size (t : LTree) : nat :=
  let size_l := (fix size_l (l : list LTree) : nat :=
                  match l with
                    | nil => 0
                    | h::r => size h + size_l r
                  end) in
  match t with Node l =>
    1 + size_l l
  end.

或者,如果您希望更简洁地编写此代码:

Fixpoint size (t : LTree) : nat :=
  match t with Node l =>
    1 + (fix size_l (l : list LTree) : nat :=
          match l with
            | nil => 0
            | h::r => size h + size_l r
          end) l
  end.

(我不知道我是从谁那里听到的;这肯定是多次独立发现的。)

通用递归谓词

通常,您可以LTree手动定义“适当的”归纳原理。自动生成的归纳原理LTree_rect忽略了列表中的假设,因为归纳原理生成器仅了解归纳类型的非嵌套严格正出现。

LTree_rect = 
fun (P : LTree -> Type) (f : forall l : list LTree, P (Node l)) (l : LTree) =>
match l as l0 return (P l0) with
| Node x => f x
end
     : forall P : LTree -> Type,
       (forall l : list LTree, P (Node l)) -> forall l : LTree, P l

让我们在列表上添加归纳假设。为了在递归调用中实现它,我们调用列表归纳原理,并将其传递给列表内较小树上的树归纳原理。

Fixpoint LTree_rect_nest (P : LTree -> Type) (Q : list LTree -> Type)
                         (f : forall l, Q l -> P (Node l))
                         (g : Q nil) (h : forall t l, P t -> Q l -> Q (cons t l))
                         (t : LTree) :=
  match t as t0 return (P t0) with
    | Node l => f l (list_rect Q g (fun u r => h u r (LTree_rect_nest P Q f g h u)) l)
  end.

为什么

原因的答案在于接受递归函数的精确规则。这些规则有些微妙,因为在允许复杂的情况(例如这种情况,在数据类型中具有嵌套递归)和不健全之间存在微妙的平衡。该勒柯克参考手册介绍了语言(感应结构的演算,它是勒柯克的证明语言),大多与正式精确的定义,但如果你想关于诱导和coinduction你需要去研究论文的具体规则,关于这个话题,爱德华多·吉米内斯(EduardoGiménez)[1]。

从Coq手册开始,在Fix规则符号中,我们有的定点定义。F一世XF一世{F1个一种1个:=Ť1个;F2一种2:=Ť2}

Γ1个=X大号Ť[RËË一种1个=ñ一种ŤŤ1个=C一种sËX大号Ť[RËËλÿG1个F2ÿΓ2=一世sŤ大号Ť[RËË一种2=ñ一种ŤŤ2=C一种sË一世sŤ大号Ť[RËËλH[RG2F1个HF2[R

FĴŤ一世F一世

  • 一世=1个Ĵ=2ltsize
  • 一世=2Ĵ=1个hlsize_l
  • 一世=2Ĵ=2rlsize_l

我在h结构上不小于lCoq解释器的原因尚不清楚。据我从Coq-club列表[1] [2]的讨论中了解到,这是解释器中的一个限制,原则上可以解除限制,但要非常小心,以免引起不一致。

参考文献

Cocorico,无止境的Coq Wiki:

Coq-Club邮件列表:

Coq开发团队。Coq证明助手:参考手册。版本8.3(2010)。[ 网络 ] 频道 4

爱德华多(EduardoGiménez)。用递归方案整理保护的定义。在Types'94:证明和程序的类型,LNCS 996中。Springer-Verlag,1994年。doi:10.1007 / 3-540-60579-7_3 [ Springer ]

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


7

这显然是Coq特有的一个问题,因为我相信有更好的方法可以与其他一些证明助手一起解决(我在研究Agda)

起初,我认为r没有人认为它在结构上更小,因为结构仅与当前由Fixpoint:处理的归纳定义有关。因此,这不是LTree子项,即使它是list子项也是如此。

但是,如果您扩展列表的处理,那么它将起作用:

Fixpoint size t :=
  match t with
  | Node l => S
     ((fix size_l l :=
     match l with
     | nil => 0
     | cons t l => size_l l + size t
     end) l)
 end.

或由于辅助功能已存在于标准库中:

Require Import List.

Fixpoint size t :=
  match t with
  | Node l => S (fold_left (fun a t => a + size t) l 0)
  end.

老实说,我不确定为什么这些被Coq接受,但是我很高兴他们被接受。

还有一种解决方案,其工作频率更高,不仅适用于列表:定义一个自包含的归纳类型。在这种情况下,您可以size手动定义功能。(带有两个固定点)

Inductive LTree : Set :=
  | Node : list_LTree -> LTree
with list_LTree : Set :=
  | LTree_nil : list_LTree
  | LTree_cons : LTree -> list_LTree -> list_LTree.

请注意,如果在使用更复杂的归纳定义时遇到问题,则可以使用减小大小的参数。这是可能的,但对于这个问题很麻烦(我敢说大多数问题)


我今天仍然不明白的是,为什么幼稚的方法行不通。原则上,这应该是EduardoGiménez的论文的结果,但是我不知道推论在何处中断。这可能是Coq引擎而不是基础演算的限制。
吉勒斯(Gilles)'所以
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.