Haskell 为什么归纳数据类型禁止像'data Bad a=C(Bad a->;a)`这样的类型,其中类型递归发生在->;之前;?
Agda国家手册: 为确保正常化,感应事件必须出现在严格的正位置。例如,不允许以下数据类型: 因为构造函数的参数中出现了负面的BadHaskell 为什么归纳数据类型禁止像'data Bad a=C(Bad a->;a)`这样的类型,其中类型递归发生在->;之前;?,haskell,recursive-datastructures,algebraic-data-types,y-combinator,agda,Haskell,Recursive Datastructures,Algebraic Data Types,Y Combinator,Agda,Agda国家手册: 为确保正常化,感应事件必须出现在严格的正位置。例如,不允许以下数据类型: 因为构造函数的参数中出现了负面的Bad 为什么归纳数据类型需要此要求?特纳,D.a.(2004-07-28)第节给出了此类数据类型如何允许我们居住在任何类型中的示例。规则2:类型递归必须是协变的 让我们用Haskell做一个更详细的例子。我们将从一个“坏”的递归数据类型开始 数据坏a=C(坏a->a) 这意味着拥有这样一种数据类型允许我们构造任何类型的递归,或者通过无限递归驻留在任何类型中 非类
为什么归纳数据类型需要此要求?特纳,D.a.(2004-07-28)第节给出了此类数据类型如何允许我们居住在任何类型中的示例。规则2:类型递归必须是协变的
让我们用Haskell做一个更详细的例子。我们将从一个“坏”的递归数据类型开始
数据坏a=C(坏a->a)
这意味着拥有这样一种数据类型允许我们构造任何类型的递归,或者通过无限递归驻留在任何类型中
非类型lambda演算中的Y组合子定义为
Y=λf.(λx.f(x x))(λx.f(x))
关键是我们在x
中将x
应用于自身。在类型化语言中,这是不可能的,因为没有x
可能具有的有效类型。但是我们的坏的
数据类型允许此模块添加/删除构造函数:
selfApp::坏a->a
selfApp(x@(cx'))=x'x
以x::Bad a
为例,我们可以展开它的构造函数,并将其中的函数应用于x
本身。一旦我们知道如何做,就很容易构造Y组合符:
yc::(a->a)->a
让fxx=C(\x->f(selfApp x))--这是Y的λx.f(x x)部分
在selfApp fxx中
请注意,selfApp
和yc
都不是递归的,函数本身没有递归调用。递归只出现在递归数据类型中
我们可以检查构造的组合器是否确实执行了它应该执行的操作。我们可以创建一个无限循环:
loop::a
循环=yc id
或者说:
gcd'::Int->Int->Int
gcd'=yc gcd0
哪里
gcd0::(Int->Int->Int)->(Int->Int->Int)
gcd0记录a b | c==0=b
|否则=记录b c
其中c=a`mod`b
您给出的数据类型很特殊,因为它是非类型lambda演算的嵌入
data Bad : Set where
bad : (Bad → Bad) → Bad
unbad : Bad → (Bad → Bad)
unbad (bad f) = f
让我们看看如何。回想一下,非类型lambda演算有以下术语:
e := x | \x. e | e e'
我们可以定义从非类型的lambda演算术语到类型为Bad
的Agda术语的翻译(尽管不在Agda中):
现在,您可以使用您最喜欢的非终止非类型lambda术语来生成类型为Bad
的非终止术语。例如,我们可以将(\x.x)(\x.x)
转换为类型为Bad
的非终止表达式,如下所示:
unbad (bad (\x -> unbad x x)) (bad (\x -> unbad x x))
虽然该类型恰好是这个参数的一种特别方便的形式,但只要稍加努力,它就可以推广到任何递归出现为负的数据类型。回答得不错。我喜欢这种优雅的方法,它有理论解释(嵌入非类型的lambda演算)。有没有可能扩展它,使它对所讨论的语言(比如说Agda)进行任意递归?@PetrPudlák所以,我刚刚和我的同事聊天,他们远远比我更好的类型理论家。大家一致认为,这种
糟糕的不会产生一个关于所有a.a
类型的术语(这正是您真正关心的;递归只是一种实现方法)。论点是这样的:你可以构建Agda的集合论模型;然后你可以将Bad
作为一个元素集添加到该模型中;因为在结果模型中仍然存在无人居住的类型,所以没有函数将循环Bad
术语转换为另一种类型的循环术语。
[[x]] = x
[[\x. e]] = bad (\x -> [[e]])
[[e e']] = unbad [[e]] [[e']]
unbad (bad (\x -> unbad x x)) (bad (\x -> unbad x x))