为什么不';t型同义词在Haskell中允许递归?

为什么不';t型同义词在Haskell中允许递归?,haskell,types,Haskell,Types,有人能解释一下为什么这两个问题都能顺利解决吗: data A a b = A { a :: a, b :: b } newtype B a = B (A a (B a)) newtype C = C (A Int C) 但是我不能通过类型同义词创建类似的递归定义的类型 type B a = A a (B a) type C = A Int C 虽然显然databa=a{a::a,B::ba}工作得很好 有没有办法避免在我想要递归类型的任何地方处理额外的构造函数X?我主要是通过访问器函数来选择

有人能解释一下为什么这两个问题都能顺利解决吗:

data A a b = A { a :: a, b :: b }
newtype B a = B (A a (B a))
newtype C = C (A Int C)
但是我不能通过类型同义词创建类似的递归定义的类型

type B a = A a (B a)
type C = A Int C
虽然显然
databa=a{a::a,B::ba}
工作得很好

有没有办法避免在我想要递归类型的任何地方处理额外的构造函数X?我主要是通过访问器函数来选择
b
,所以我基本上没问题,但是如果存在一个简单的规避机制,我想知道它

我应该使用哪些pragma来提高专用数据类型C的性能?只是专门做些什么


aab
acd
之间复制有没有聪明的技巧,只定义
A->b
c->d
映射而不复制记录两次?我担心
A
的字段将来会改变。也许是哈斯克尔

我会回答你的第一个问题和第二个问题

B的类型是无限类型(A A(A A(A A(…)))))

“类型推断引擎”可以设计为推断和处理无限类型。不幸的是,程序员的许多错误(排版错误或逻辑错误)创建的代码没有达到所需的有限类型,并且意外地具有无限类型。现在编译器拒绝这样的代码,这几乎总是程序员想要的。将其更改为允许无限类型将在编译时造成更难理解的错误(至少与C++模板一样糟糕),并且在极少数情况下,可能会使其编译并在运行时错误地执行。 有没有办法避免处理额外的构造函数X 我想要递归类型的任何地方

否。Haskell已选择只允许递归类型
数据
新类型
中的显式类型构造函数。这使得代码更加冗长,但是
newtype
应该不会对运行时造成什么损失。这是一个设计决策。

这与VS有关。Haskell使用iso递归类型实现递归类型,这要求程序员在发生类型递归时告诉类型检查器。标记它的方式是使用特定的构造函数,而简单的类型同义词不允许使用该构造函数

等递归类型允许编译器推断递归发生的位置,但它会导致更复杂的类型检查器,在某些看似简单的情况下,问题是无法确定的

如果你想好好讨论equi和iso递归类型,可以看看benjaminpierce的优秀文章


简短回答:因为类型同义词不引入构造函数,haskell需要构造函数在类型级别显式标记递归,所以不能使用递归类型同义词。

newtype
对GHC没有任何运行时惩罚。我不确定这是否是报告所要求的,但我似乎记得与所要求的包装类型相同的表示形式。啊,是的,如果不小心的话,我想这可能是偶然发生的,但otoh
B
只是循环链接列表的类型,对于Haskell来说没有什么不寻常的。啊,哎呀,哈斯克尔似乎比我想象的更不喜欢我的唱片了。
newtype Foo t=Foo t
并没有运行时惩罚
map Foo
是将
[t]
转换为
[Foo t]
的安全方法。它确实如此,但并不便宜。一个类型检查器应该如何比较无限类型的相等性呢?@trinithis:是的;一般来说,您可以安全地
unsafeccerce
消除
newtype
与其表示形式之间的任何差异。啊,谢谢您的参考。如果我理解正确,类型的
对于所有a
实际上意味着“除了我以外的所有人”。这是必要的,因为程序员必须在递归发生时告诉它。不,对于所有a
与多态性有关。实际上,创建递归类型不需要类型参数<代码>数据A=A A
非常好。问题是haskell在决定术语的类型时,必须知道在哪里停止“向下钻取”。当它找到构造函数时,它知道在计算整个术语的类型时,它不必深入到该子术语。在
数据A=A A A
中没有任何
forall
,但是,
forall
仅在类型保持未指定时出现,这需要这个
newtype
技巧。我以为你在问
forall
是否与递归类型有关。没有。我只是说,每当你有任何类型的递归类型时,都需要“newtype技巧”,不管它是否是多态的(有未指定的类型)。我一直想知道为什么Haskell不允许无限类型(它总是允许无限数据)。有“正确”吗无需模式绑定或写入
unC(ca)=a
someplace就可以删除构造函数
C
的方法?newtype C=C{unC::a Int C}
做你想做的吗?我想这是等效的,只是询问是否有一些标准技巧。如果一个值在GHC中有一个
newtype
构造函数,您可以使用
unsafeccerce
:)将其删除