【问题标题】:Difference between `data` and `newtype` in HaskellHaskell中`data`和`newtype`之间的区别
【发布时间】:2011-08-18 21:10:57
【问题描述】:

我写这个有什么区别?

data Book = Book Int Int

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

【问题讨论】:

标签: haskell types type-systems newtype


【解决方案1】:

好问题!

有几个关键的区别。

代表

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

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

例子:

  • data Book = Book Int Int

  • newtype Book = Book (Int, Int)

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

  • data Book = Book (Int, Int)

newtype 中没有额外的Book 构造函数。

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

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

代数数据类型

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

data Maybe a = Nothing
             | Just a

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

newtype Book = Book Int Int

严格

构造函数被擦除的事实导致datanewtype 之间的严格性存在一些非常细微的差异。特别是,data 引入了一种“提升”的类型,本质上意味着它有一种额外的方法来评估底部值。由于newtype 在运行时没有额外的构造函数,所以这个属性不成立。

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

因此,newtypedata 的严格性属性略有不同,如 explained in the Haskell wiki article

拆箱

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

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

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


参考文献

【讨论】:

  • 如果 Haskell 中没有“新类型”,我仍然认为我不会错过任何东西。细微的差异增加了语言的复杂性,对我来说似乎不值得......
  • 由于性能原因,差异非常有用。由于 newtype 构造函数在编译时被擦除,因此它们不会像数据构造函数那样对运行时性能造成损失。但是它们仍然为您提供了完全不同类型的所有好处以及您想要与之关联的任何抽象。例如,列表数据类型可以通过两种不同的方式形成 monad。一种是内置在语言中的,但如果你想使用另一种,一种新类型将是可行的方法。
  • 很好的解释!我不明白的是,如果 newtype 在编译后被删除,运行时对新旧类型使用相同的表示,我们如何仍然能够为新旧类型定义实例?运行时如何理解使用哪个实例?
  • @damluar 所有类型在运行时被擦除,在编译时都被完全解析,而在编译过程中newtype显然还没有被擦除。
  • @damlaur 我曾经和你有同样的问题。当人们说类型被擦除时,他们忽略了提到 ISN'T erased 的一件事,这是一个记忆词,用于字典查找以决定对给定数据使用哪种实例方法。人们争辩说这个词不是“类型”,我认为这取决于你的观点,但你去吧。
猜你喜欢
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 2015-06-28
相关资源
最近更新 更多