これを書いたときの違いは何ですか?
data Book = Book Int Int
対
newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
newtype Book = Book Int Int
無効であることに注意してください。ただし、newtype Book = Book (Int, Int)
以下のドンによって示されるようにすることができます。
これを書いたときの違いは何ですか?
data Book = Book Int Int
対
newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
newtype Book = Book Int Int
無効であることに注意してください。ただし、newtype Book = Book (Int, Int)
以下のドンによって示されるようにすることができます。
回答:
すばらしい質問です。
いくつかの重要な違いがあります。
表現
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
はないため、このプロパティは保持されません。
Book
to (,)
コンストラクターの追加のポインターにより、底値を入れることができます。
結果として、newtype
そしてdata
ように、わずかに異なる厳密性を有するHaskellのウィキの記事で説明。
開梱
コンストラクタがないため、のコンポーネントのボックス化を解除しても意味がありませんnewtype
。書くことは完全に合理的ですが:
data T = T {-# UNPACK #-}!Int
T
コンストラクターとInt#
コンポーネントを含むランタイムオブジェクトを生成します。あなただけで裸にInt
なりnewtype
ます。
参照:
newtype
コンパイル後に消去され、ランタイムが古いタイプと新しいタイプに同じ表現を使用する場合、どうすれば古いタイプと新しいタイプの両方のインスタンスを定義できるでしょうか?ランタイムはどのインスタンスを使用するかをどのように理解できますか?
newtype
は明らかにまだ消去されていません。