Haskell中data和newtype之间的区别


191

我写这篇文章有什么区别?

data Book = Book Int Int

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

您应该进行一些搜索,该问题已经得到解答。stackoverflow.com/questions/2649305/…–
德曼



25
请注意,这newtype Book = Book Int Int是无效的。但是,您可以newtype Book = Book (Int, Int)按照下面的说明进行操作。
爱德华KMETT

Answers:


241

好问题!

有几个主要区别。

表示

  • A newtype保证您的数据在运行时将具有与包装的类型完全相同的表示形式。
  • 虽然data在运行时声明了全新的数据结构。

因此,这里的关键newtype是保证在编译时会删除的构造。

例子:

  • data Book = Book Int Int

数据

  • newtype Book = Book (Int, Int)

新类型

请注意(Int,Int),由于Book删除了构造函数,因此它的表示形式与完全相同。

  • data Book = Book (Int, Int)

数据元组

中没有其他Book构造函数newtype

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

在此处输入图片说明

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

代数数据类型

由于需要擦除构造函数,因此newtype只有在用单个构造函数包装数据类型时,a 才起作用。没有“代数”新类型的概念。也就是说,您不能编写与以下内容等效的新类型:

data Maybe a = Nothing
             | Just a

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

newtype Book = Book Int Int

严格

删除构造函数的事实导致data和之间的严格性差异非常细微newtype。特别是,data引入了一种“提升”类型,从本质上讲,它意味着可以使用其他方法求出底值。由于使用时在运行时没有其他构造函数newtype,因此该属性不成立。

Bookto (,)构造函数中的额外指针使我们可以放入一个底值。

作为结果,newtypedata具有略微不同的严格性,因为Haskell的维基文章中解释

拆箱

取消对a的组件拆箱是没有意义的newtype,因为没有构造函数。虽然写是完全合理的:

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

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


参考文献


2
如果Haskell中没有“新类型”,我仍然不会错过任何东西。微妙的差异增加了我似乎不值得使用的语言的复杂性……
martingw

14
出于性能原因,差异非常有用。由于newtype构造函数在编译时被擦除,因此它们不会像数据构造函数那样施加运行时性能损失。但是它们仍然为您提供完全独特的类型以及您希望与之关联的任何抽象的所有优点。例如,列表数据类型可以采用两种不同的方式形成monad。一种语言内置于该语言中,但是如果您想使用另一种语言,则应该使用新类型。
强大字节

很好的解释!我不明白的是,如果newtype在编译和运行时对旧类型和新类型使用相同的表示形式后将其擦除,那么我们如何仍然能够为旧类型和新类型定义实例?运行时如何理解要使用哪个实例?
damluar '16

3
@damluar所有类型都在运行时删除,它们在编译时已完全解析,并且在编译newtype过程中显然尚未删除。
分号

3
@damlaur我曾经和你有同样的问题。当人们说类型被擦除时,他们会忽略提及IS N'T未被擦除的一件事,这是一个内存词,用于字典查找,以确定对给定数据使用哪种实例方法。人们认为这个词不是“类型”,我认为这取决于您的观点,但是您可以使用。
加布里埃尔·
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.