我一直在用“旧”和“新”方法在 Agda 中处理共归纳法进行一些实验,但我认为我仍然遗漏了一些关于 Agda 在不使用Size
时对核心递归函数的终止检查行为的重要事实。
例如,考虑 和 的以下Stream
定义repeat
:
data Stream (A : Set) : Set
record ∞Stream (A : Set) : Set where
coinductive
field force : Stream A
open ∞Stream
data Stream A where
cons : A -> ∞Stream A -> Stream A
repeat : ∀{A} -> A -> ∞Stream A
force (repeat x) = cons x (repeat x)
粗略地说,协约记录类型∞Stream
是专门Thunk
用于流的。我在很多 Agda 形式化中看到了类似的定义,尽管它们通常被改进为 aSize
以获得更好的精度。无论如何,上面的定义repeat
被 Agda 接受,没有任何Size
注释。
问题是当我尝试将∞Stream
记录分解为 aThunk
时,以便我可以Thunk
在其他地方重用以定义其他可能无限的数据类型:
record Thunk (A : Set) : Set where
coinductive
field force : A
open Thunk
data Stream (A : Set) : Set where
cons : A -> Thunk (Stream A) -> Stream A
repeat : ∀{A} -> A -> Thunk (Stream A)
force (repeat x) = cons x (repeat x)
注意:
- 两种情况下的代码
repeat
完全相同, repeat
在每种情况下,都会在构造函数的下方找到递归调用cons
,- 在每种情况下都会
repeat
产生一个共归纳记录类型的值,
然而 Agda 接受第一个定义repeat
但拒绝第二个定义(以下函数的终止检查失败:repeat)。
我知道使用Thunk
标准库中的大小可以修改第二个版本,以便被 Agda 接受。尽管如此,我想了解是什么让上面的第一个版本与第二个版本如此不同,以至于它通过了终止检查器。在我看来,它们基本相同。
谢谢!