Recursion 如何证明递归列表长度的终止?

Recursion 如何证明递归列表长度的终止?,recursion,termination,reasoning,formal-verification,formal-methods,Recursion,Termination,Reasoning,Formal Verification,Formal Methods,假设我们有一个列表: List = nil | Cons(car cdr:List). 注意,我说的是可修改列表! 和一个简单的递归长度函数: recursive Length(List l) = match l with | nil => 0 | Cons(car cdr) => 1 + Length cdr end. 当然,它仅在列表为非循环时终止: inductive NonCircular(List l) = { empty: NonCircular(n

假设我们有一个列表:

List = nil | Cons(car cdr:List).
注意,我说的是可修改列表! 和一个简单的递归长度函数:

recursive Length(List l) = match l with
   | nil => 0
   | Cons(car cdr) => 1 + Length cdr
end.
当然,它仅在列表为非循环时终止:

inductive NonCircular(List l) = {
   empty: NonCircular(nil) |
   \forall head, tail: NonCircular(tail) => NonCircular (Cons(head tail))
}
请注意,此谓词作为递归函数实现,也不会在循环列表上终止

通常我看到列表遍历终止的证明,使用列表长度作为有界递减因子。他们假设
Length
是非负的。但是,在我看来,这个事实(
Length l>=0
)源自于
Length
的终止

您如何证明
长度
终止并且在
非循环
(或等效的、定义更好的谓词)列表上是非负的


我是否遗漏了一个重要的概念?

除非长度函数具有循环检测功能,否则无法保证它会停止

对于单链表,可以使用来确定
cdr
中可能存在圆圈的长度

只有两个光标,乌龟从第一个元素开始,兔子从第二个元素开始。乌龟一次移动一个指针,而兔子移动两个指针(如果可以的话)。兔子最终要么和乌龟一样,表示一个循环,要么在知道长度为2*步或2*步+1时终止


与在树中查找循环相比,这非常便宜,并且在终止列表上的性能与没有循环检测的函数一样好

顶部的列表定义似乎不允许循环列表。每次调用“构造函数”Cons都将创建一个新指针,以后不允许修改指针来创建循环

如果你想处理循环,你需要一个更复杂的列表定义。您可能需要定义一个包含数据值和地址的单元格,以及一个包含指向前一个节点的单元格和地址的节点,然后您需要定义解引用运算符,以便从地址返回到单元格。也可以尝试在此对象上定义非圆形

我的直觉是,你还需要定义一个内射函数,从上面的“简单”列表定义到我概述的复杂列表定义,最后你将能够证明你的结果

另外,非循环的定义不需要终止。这不是一个程序,而是一个证明。如果它成立,那么你可以检查证明,看看为什么它成立,并在其他证明中使用这一点。
编辑:感谢Necto指出我错了。

除了最后一段,我同意。终止对于证明程序至关重要。否则,这里是false的证明:
f:true->false:={return f();}