Haskellの `data`と` newtype`の違い


191

これを書いたときの違いは何ですか?

data Book = Book Int Int

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

いくつか検索してみてください。この質問はすでに回答されています。stackoverflow.com/questions/2649305/...
tehman


また関連:newtypeのための用途:stackoverflow.com/questions/991467/...
ドン・スチュワート

25
newtype Book = Book Int Int無効であることに注意してください。ただし、newtype Book = Book (Int, Int)以下のドンによって示されるようにすることができます。
エドワードKMETT、2011

回答:


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

ここに画像の説明を入力してください

ポインタはありません!2つのIntフィールドは、Bookコンストラクターのボックス化されていないワードサイズのフィールドです。

代数的データ型

これはコンストラクターを消去する必要があるためnewtype、データ型を単一のコンストラクターでラップする場合にのみ機能します。「代数的」な新しいタイプの概念はありません。つまり、たとえば、次のような同等のnewtypeを作成することはできません。

data Maybe a = Nothing
             | Just a

複数のコンストラクタがあるためです。あなたも書けない

newtype Book = Book Int Int

厳格

コンストラクターが消去されるという事実は、dataとの厳密性に非常に微妙な違いをもたらしnewtypeます。特に、data「リフト」されるタイプを導入します。これは、本質的に、ボトム値に評価する追加の方法があることを意味します。を使用して実行時に追加のコンストラクタnewtypeはないため、このプロパティは保持されません。

Bookto (,)コンストラクターの追加のポインターにより、底値を入れることができます。

結果として、newtypeそしてdataように、わずかに異なる厳密性を有するHaskellのウィキの記事で説明

開梱

コンストラクタがないため、のコンポーネントのボックス化を解除しても意味がありませんnewtype。書くことは完全に合理的ですが:

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

TコンストラクターとInt#コンポーネントを含むランタイムオブジェクトを生成します。あなただけで裸にIntなりnewtypeます。


参照


2
Haskellに「newtype」がなかったとしても、何かを見逃すことはないと思います。微妙な違いにより、私にはふさわしくないと思われる言語に複雑さが追加されます...
martingw

14
この違いは、パフォーマンス上の理由から非常に役立ちます。newtypeコンストラクターはコンパイル時に消去されるため、データコンストラクターが実行時のパフォーマンスを低下させることはありません。しかし、それでも完全に異なるタイプのすべての利点と、それに関連付けたいあらゆる抽象化を提供します。たとえば、リストのデータ型がモナドを形成する方法は2つあります。1つは言語に組み込まれていますが、もう1つを使用したい場合は、newtypeが適しています。
11

素晴らしい説明!私が理解していないのは、newtypeコンパイル後に消去され、ランタイムが古いタイプと新しいタイプに同じ表現を使用する場合、どうすれば古いタイプと新しいタイプの両方のインスタンスを定義できるでしょうか?ランタイムはどのインスタンスを使用するかをどのように理解できますか?
damluar

3
@damluarすべてのタイプは実行時に消去され、すべてコンパイル時に完全に解決され、コンパイル中newtypeは明らかにまだ消去されていません。
セミコロン

3
@damlaur私はかつてあなたと同じ質問をしました。型が消去されたと言うとき、ISNが消去されなかったことの1つは言及されません。これは、特定のデータに使用するインスタンスメソッドを決定するための辞書検索に使用されるメモリワードです。この言葉は「タイプ」ではないと人々は主張しますが、これはあなたの視点に依存すると私は思いますが、そこに行きます。
Gabriel L.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.