为什么Coq递归原则同时传递子结构和递归调用的结果?

为什么Coq递归原则同时传递子结构和递归调用的结果?,coq,Coq,在检查了为不同递归数据类型生成的几个不同的递归原则之后,我注意到在递归情况下,子结构与子结构上递归调用的结果一起传递 例如,执行Print list_rect可提供: list_rect = fun (A : Type) (P : list A -> Type) (f : P nil) (f0 : forall (a : A) (l : list A), P l -> P (a :: l)%list) => fix F (l : list A) : P l := mat

在检查了为不同递归数据类型生成的几个不同的递归原则之后,我注意到在递归情况下,子结构与子结构上递归调用的结果一起传递

例如,执行
Print list_rect
可提供:

list_rect =
fun (A : Type) (P : list A -> Type) (f : P nil)
  (f0 : forall (a : A) (l : list A), P l -> P (a :: l)%list) =>
fix F (l : list A) : P l :=
  match l as l0 return (P l0) with
  | nil => f
  | (y :: l0)%list => f0 y l0 (F l0)
  end
     : forall (A : Type) (P : list A -> Type),
       P nil ->
       (forall (a : A) (l : list A), P l -> P (a :: l)%list) ->
       forall l : list A, P l

在模式匹配中,cons的大小写看起来像
(y::l0)%list=>f0 y l0(F l0)
。为什么
f0
同时接受
l0
和递归调用
F
l0
的结果?当您已经计算了调用
F
的结果时,您需要访问列表尾部的情况是什么

一旦你需要归纳假设,你就需要列表的尾部,因为它以其类型出现:
pl
l
需要在范围内


现在,如果您不担心类型,那么同时拥有列表尾部和递归调用的一个很好的理由是效率:计算尾部在列表大小上是线性的,但在途中获取它是恒定的时间。这类问题的典型示例是当您只能访问迭代器而不能访问递归器时。

有关递归器与迭代器的更多信息,请参见,第节。9.1(系统T)。在不需要折叠尾部的特殊情况下,是否合适?你只需要尾巴的特殊情况有名字吗?