为什么不在Haskell中输入同义词允许递归?

Jef*_*ges 20 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)
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 bA c d定义a -> bc -> 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应该有很少的运行时惩罚.这是一个设计决定.

  • `newtype`在GHC上根本没有运行时惩罚.我不确定报告是否需要这个,但我似乎记得要求的包装类型的相同表示. (4认同)
  • 'newtype Foo t = Foo t`没有运行时惩罚并不完全正确.`map Foo`是将`[t]`变成`[Foo t]`的安全方法.它确实很干净,但并不便宜. (4认同)