谁能解释为什么这两个都快乐地编译:
data A a b = A { a :: a, b :: b }
newtype B a = B (A a (B a))
newtype C = C (A Int C)
Run Code Online (Sandbox Code Playgroud)
但我不能通过类型同义词创建类似的递归定义类型?
type B a = A a (B a)
type C = A Int C
Run Code Online (Sandbox Code Playgroud)
虽然显然data B a = A { a :: a, b :: B a }
效果很好.
有没有办法避免处理那个额外的构造函数X,我希望类型递归?我主要传递的是访问器功能,b
无论如何都要选择,所以我很好,但如果存在简单的规避机制,我想知道它.
我应该用什么编译指示来提高专用数据类型C的性能?只是专攻东西?
在没有复制记录两次的情况下复制A a b
和A c d
定义a -> b
和c -> d
映射的任何巧妙技巧?我担心A
未来的领域会发生变化.模板Haskell也许?
deo*_*ian 29
这与Equi-recursive类型和iso-recursive类型有关.Haskell使用iso-recursive类型实现递归类型,这需要程序员在类型递归发生时告诉类型检查器.标记它的方式是使用特定的构造函数,简单的类型同义词不允许您使用.
等递归类型允许编译器推断出递归发生的位置,但它导致更复杂的类型检查器,并且在一些看似简单的情况下,问题是不可判定的.
如果您想对equi与iso递归类型进行良好讨论,请查看Benjamin Pierce的优秀类型和编程语言
简短回答:因为类型同义词不引入构造函数,并且haskell需要构造函数在类型级别显式标记递归,所以不能使用递归类型同义词.
Chr*_*icz 15
我会回答你的第一个问题和第二个问题.
B的类型是无限类型(A a(A a(A a(A a(...)))))
"类型推理引擎"可以设计用于推断和处理无限类型.不幸的是,程序员的许多错误(印刷的或逻辑的)创建的代码无法具有所需的有限类型,并且意外地和意外地具有无限类型.现在编译器拒绝这样的代码,这几乎总是程序员想要的.将其更改为允许无限类型会在编译时创建更难理解的错误(至少与C++模板一样糟糕),并且在极少数情况下,您可能会在运行时编译并执行错误.
有没有办法避免处理那个额外的构造函数X,我希望类型递归?
不,Haskell选择仅允许使用data
或的显式类型构造函数的递归类型newtype
.这些使代码更加冗长,但newtype
应该有很少的运行时惩罚.这是一个设计决定.