是否有功能语言可以在类型检查器中指定某个计算是否可以保证终止?或者,您可以在Haskell中执行此操作吗?
关于Haskell,在this answer中,海报上写着
通常的思考方式是每个Haskell类型都被“解除” - 它包含⊥。也就是说,
Bool
对应{⊥, True, False}
而非{True, False}
。这表示Haskell程序不能保证终止并且可能有例外。
另一方面,this paper about Agda表示
正确的Agda程序是通过类型检查和 终止检查
即,所有Agda程序都将终止,Agda中的Bool
完全对应{True, False}
。
例如,在Haskell中,您可以拥有类型IO a
的值,它告诉类型检查器需要IO来计算相关值。你有一个类型Lifted a
断言有问题的计算可能不会终止吗?也就是说,您允许非终止,但在类型系统中将其分开。 (显然,就像在Agda中一样,你只能将值分成“绝对终止”和“可能不会终止”)如果没有,是否有语言可以做到这一点?
答案 0 :(得分:4)
你当然可以。然而,它并不完美。根据定义,一些终止的计算必须驻留在Lifted
中。这被称为暂停问题。
现在,在你放弃这个想法之前,听起来并不是那么糟糕。 Coq,Agda和其他许多人都可以使用启发式方法来检查终止。
这些真正重要的语言就像Coq和Agda那样,你试图证明这些定理。例如,假设我们有类型
Definition falsy := exists n, n > 0 /\ 0 > n.
-- Read this as,
-- "The type of a proof that for some number n, n > 0 and n < 0"
在Coq语法中。 /\
表示和。现在要在Coq或Agda中证明这样的属性,我们必须编写像
Definition out_proof : falsy = ____.
-- Read this as
-- "A proof that there exists a number n < 0 and n > 0"
其中____
证明某些号码n
,n > 0
和0 > n
。现在这非常困难,因为falsy
是假的。显然,不存在小于和大于0的数字。
但是,如果我们允许使用无限递归进行无条件化,
Definition bottom_proof : falsy = bottom_proof.
此类型检查,但显然不一致!我们刚刚证明了一些错误!因此,定理证明助手强制执行某种形式的终止检查,否则它们就毫无价值。
如果你想要务实,你可以使用这种提升类型基本上告诉typechecker,“退后,我知道这可能不会终止,但我很好”。这有助于编写现实世界的东西,比如说,网络服务器或任何你可能希望它“永远”运行的东西。
从本质上讲,你提出了语言上的分歧,一方面,你有“经过验证的代码”,你可以安全地证明这一点,另一方面,你有“不安全的代码”,它可以永远循环。你对IO
的比较是正确的。这与Haskell对副作用的划分完全相同。
你提到了corecursive数据,但这不是你想要的。这个想法是你永远循环,但你“有效地”这样做。从本质上来说,递归检查终止的最简单方法就是你总是使用一个严格小于你现有条件的术语进行递归。
Fixpoint factorial n := match n with
| 0 => 1
| S n' => n * factorial n'
对于corecursion,你得到的术语必须比输入“更大”。
Cofixpoint stream := Cons 1 stream
同样这不允许
Cofixpoint stream := stream