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)
请注意它是如何具有完全相同的表示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”
- 诺曼·拉姆齐关于严格性的答案