Recursion agda中递归函数调用的终止检查

Recursion agda中递归函数调用的终止检查,recursion,agda,termination,coinduction,Recursion,Agda,Termination,Coinduction,以下代码在Haskell中完全可以使用: dh :: Int -> Int -> (Int, Int) dh d q = (2^d, q^d) a = dh 2 (fst b) b = dh 3 (fst a) Agda中的类似代码无法编译(终止检查失败): a的定义使用了a,它在结构上不是更小的,因此是循环。似乎终止检查器不会查看dh的定义 我尝试过使用coinduction,设置选项——终止深度=4——没有帮助。 在mutual块中插入{-#NO#u TERMINATION_C

以下代码在Haskell中完全可以使用:

dh :: Int -> Int -> (Int, Int)
dh d q = (2^d, q^d)
a = dh 2 (fst b)
b = dh 3 (fst a)
Agda中的类似代码无法编译(终止检查失败):

a
的定义使用了
a
,它在结构上不是更小的,因此是循环。似乎终止检查器不会查看
dh
的定义

我尝试过使用coinduction,设置选项
——终止深度=4
——没有帮助。 在
mutual
块中插入
{-#NO#u TERMINATION_CHECK#-}
会有所帮助,但看起来像是作弊


有没有一种干净的方法让Agda编译代码?Agda的终止检查程序是否有一些基本的限制?

Agda不像Haskell那样假设延迟评估。相反,Agda要求所有表达式都进行强规范化。这意味着您应该得到相同的答案,而不管您计算子表达式的顺序如何。您给出的定义不是严格规范化的,因为存在一个不会终止的求值顺序:

a
-->
dh 2 (proj₁ b)
-->
dh 2 (proj₁ (dh 3 (proj₁ a))
-->
dh 2 (proj₁ (dh 3 (proj₁ (dh 2 (proj₁ b)))))
特别是,Agda的JavaScript后端将生成不会终止于
a
b
的代码,因为JavaScript是经过严格评估的


检查强规范化程序的子集:那些只有结构递归的程序。它查看函数定义中匹配的构造函数模式的数量和顺序,以确定递归调用是否使用“较小”的参数
a
b
没有任何参数,因此终止检查器将从
a
a
(通过
b
)的嵌套调用视为相同的“大小”作为
a
本身。

我还不太熟悉corecursion,所以我没有评论它是否可以用于您的优势。我同意您的看法。但是从另一个角度来看,
dh
的结果只是一对
s,对
a
b
的评估可以分解为:
aQ=2^ad;bQ=2^bd;abQ=bQ^ad;baQ=aQ^bd
。甚至不需要
mutual
关键字。
dh
的要点是增加算法的步骤,并抽象出计算顺序。在分解形式中,代码变得过于冗长。
a
-->
dh 2 (proj₁ b)
-->
dh 2 (proj₁ (dh 3 (proj₁ a))
-->
dh 2 (proj₁ (dh 3 (proj₁ (dh 2 (proj₁ b)))))