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

ewg*_*egw 179 haskell types type-systems newtype

我写这个有什么区别?

data Book = Book Int Int
Run Code Online (Sandbox Code Playgroud)

newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
Run Code Online (Sandbox Code Playgroud)

Don*_*art 227

好问题!

有几个关键的区别.

表示

  • 一个newtype保证您的数据将会有确切的在运行时相同的表示,为你包的类型.
  • 虽然data在运行时声明了一个全新的数据结构.

所以这里的关键点newtype是保证在编译时擦除构造.

例子:

  • data Book = Book Int Int

数据

  • newtype Book = Book (Int, Int)

NEWTYPE

请注意它与a的表示形式完全相同(Int,Int),因为Book构造函数已被删除.

  • data Book = Book (Int, Int)

数据元组

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

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

在此输入图像描述

没有指针!这两个Int字段是Book构造函数中未装箱的字大小字段.

代数数据类型

由于需要擦除构造函数,因此newtype仅在使用单个构造函数包装数据类型时才有效.没有"代数"新类型的概念.也就是说,你不能写一个相当于的新类型,比方说,

data Maybe a = Nothing
             | Just a
Run Code Online (Sandbox Code Playgroud)

因为它有多个构造函数.你也写不出来

newtype Book = Book Int Int
Run Code Online (Sandbox Code Playgroud)

严格

该构造被删除,这一事实导致之间严格一些非常细微的差别datanewtype.特别是,data引入了一种"提升"的类型,基本上意味着它有一种额外的方式来评估底值.由于运行时没有其他构造函数newtype,因此该属性不成立.

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

因此,newtype并且data具有稍微不同的严格性属性,如Haskell wiki文章中所述.

拆箱

取消打包a的组件是没有意义的newtype,因为没有构造函数.虽然写下来是完全合理的:

data T = T {-# UNPACK #-}!Int
Run Code Online (Sandbox Code Playgroud)

使用T构造函数和Int#组件生成运行时对象.你只是得到一个裸Intnewtype.


参考文献:

  • 由于性能原因,差异非常有用.由于newtype构造函数在编译时被擦除,因此它们不会强加数据构造函数所执行的运行时性能损失.但它们仍然可以为您提供完全不同类型的所有好处以及您想要与之关联的任何抽象.例如,列表数据类型可以通过两种不同的方式形成monad.一种是内置于语言中,但是如果你想使用另一种语言,那么新的类型将是最佳选择. (13认同)
  • @damlaur 我曾经和你有同样的问题。当人们说类型被擦除时,他们忽略了一个东西是不被擦除的,它是一个用于字典查找的记忆词,以确定对给定的数据使用什么实例方法。人们争辩说这个词不是“类型”,我认为这取决于您的观点,但是您去了。 (5认同)
  • @damluar所有类型都在运行时被擦除,它们都在编译时完全解析,并且在编译期间`newtype`显然还没有被删除. (3认同)
  • 如果 Haskell 中没有“newtype”,我仍然认为我不会错过任何东西。细微的差异增加了语言的复杂性,对我来说似乎不值得...... (2认同)