Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么归纳数据类型禁止像'data Bad a=C(Bad a->;a)`这样的类型,其中类型递归发生在->;之前;?_Haskell_Recursive Datastructures_Algebraic Data Types_Y Combinator_Agda - Fatal编程技术网

Haskell 为什么归纳数据类型禁止像'data Bad a=C(Bad a->;a)`这样的类型,其中类型递归发生在->;之前;?

Haskell 为什么归纳数据类型禁止像'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) 这意味着拥有这样一种数据类型允许我们构造任何类型的递归,或者通过无限递归驻留在任何类型中 非类

Agda国家手册:

为确保正常化,感应事件必须出现在严格的正位置。例如,不允许以下数据类型:

因为构造函数的参数中出现了负面的Bad


为什么归纳数据类型需要此要求?

特纳,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))