Haskell中`data`和`newtype`之间的区别

我写这个有什么不同?

data Book = Book Int Int newtype Book = Book(Int, Int) -- "Book Int Int" is syntactically invalid 

好问题!

有几个关键的区别。

表示

  • newtype保证你的数据在运行时的performance与你包装的types完全一样。
  • data在运行时声明一个全新的数据结构。

所以这里的关键是保证新types的构造在编译时被删除。

例子:

  • data Book = Book Int Int

数据

  • newtype Book = Book (Int, Int)

NEWTYPE

请注意它是如何具有完全相同的表示forms(Int,Int) ,因为Book构造函数被擦除。

  • data Book = Book (Int, Int)

数据元组

有一个额外的Book构造函数不在newtype

  • data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int

在这里输入图像描述

没有指针! 这两个Int字段是Book构造函数中的非字盒大小字段。

代数数据types

由于需要擦除构造函数,只有在用一个构造函数包装数据types时才能使用新types。 没有“代数”新型的概念。 也就是说,你不能写一个新的types,比如说,

 data Maybe a = Nothing | Just a 

因为它有多个构造函数。 你也不能写

 newtype Book = Book Int Int 

严格

构造函数被删除的事实导致了data和新types之间严格的细微差别。 尤其是, data引入了一种被“提升”的types,实质上意味着它有一种额外的方式来评估最低价值。 由于在运行时没有使用newtype附加构造函数,所以此属性不成立。

Book to (,)构造函数中的额外指针允许我们将底部值放入。

因此,新types和data严格属性稍有不同,正如Haskell wiki文章中所解释的那样 。

拆箱

因为没有构造函数,所以拆开newtype的组件是没有意义的。 尽pipe写作是完全合理的:

 data T = T {-# UNPACK #-}!Int 

产生带有T构造函数的运行时对象和一个Int#组件。 你只是得到一个newtype Int


参考文献

  • Haskell wiki上的“Newtype”
  • 诺曼·拉姆齐关于严格性的答案