假设我们有一个清单:
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
的终止。
您如何证明Length
在NonCircular
(或等效的,更明确的谓词)列表中终止并且是否定的?
我在这里错过了一个重要的概念吗?
答案 0 :(得分:0)
除非长度函数有循环检测,否则无法保证它会停止!
对于单个链接列表,可以使用Tortoise and hare algorithm来确定cdr
中可能存在圆圈的长度。
只有两个游标,乌龟从第一个元素开始,野兔从第二个元素开始。乌龟一次移动一个指针,而兔子移动两个(如果可以的话)。野兔最终要么与乌龟相同,这表示一个循环,否则它将终止,知道长度是2 *步或2 *步+ 1。
与在树中查找循环相比,这非常便宜,并且在终止列表时也可以作为没有循环检测的函数执行。
答案 1 :(得分:0)
您拥有的List的定义似乎不允许循环列表。每次调用"构造函数" Cons将创建一个新指针,并且您不允许稍后修改指针以创建圆形。
如果要处理循环,则需要更复杂的List定义。您可能需要定义包含数据值和地址的Cell,以及包含Cell和指向前一个节点的地址的Node,然后您需要定义解除引用运算符以从地址返回到Cells 。您还可以尝试在此对象上定义非圆形。
我的直觉是你还需要从"简单"中定义一个内射函数。您已经在上面列出了我已经列出的复杂的列表定义,然后最后您将能够证明您的结果。
另一件事,NonCircular的定义不需要终止。它不是一个程序,它是一个证据。如果它成立,那么您可以检查证明,看看它为什么成立并在其他证明中使用它。
编辑:感谢Necto指出我错了。