これを書くときの違いは何ですか?
data Book = Book Int Int
versus
newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
いい質問です!
いくつかの重要な違いがあります。
表現
newtype
は、データが実行時にラップする型とまったく同じ表現を持つことを保証します。data
は、実行時にまったく新しいデータ構造を宣言します。そのため、ここで重要なのは、newtype
のコンストラクトがコンパイル時に確実に消去されることです。
例:
data Book = Book Int Int
_newtype Book = Book (Int, Int)
Book
コンストラクターが消去されるため、_(Int,Int)
_とまったく同じ表現になることに注意してください。
data Book = Book (Int, Int)
Book
に存在しない追加のnewtype
コンストラクターがあります。
data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int
_ポインターなし! 2つのInt
フィールドは、Book
コンストラクター内のボックス化されていないWordサイズのフィールドです。
代数的データ型
このため、コンストラクターを消去する必要があるため、newtype
は、データ型を単一のコンストラクターでラップする場合にのみ機能します。 「代数」ニュータイプの概念はありません。つまり、たとえば、と同等のnewtypeを書くことはできません
_data Maybe a = Nothing
| Just a
_
コンストラクターが複数あるためです。また書くことはできません
_newtype Book = Book Int Int
_
厳格さ
コンストラクターが消去されるという事実は、data
とnewtype
の間の厳密さのいくつかの非常に微妙な違いにつながります。特に、data
は「リフト」されたタイプを導入します。つまり、基本的に、ボトム値を評価する追加の方法があることを意味します。実行時にnewtype
を持つ追加のコンストラクターがないため、このプロパティは保持されません。
Book
内の_(,)
_コンストラクターへの追加のポインターにより、ボトム値を入れることができます。
その結果、newtype
とdata
の厳密性のプロパティは、 Haskell wiki記事で説明されている のようにわずかに異なります。
ボックス化解除
コンストラクタがないため、newtype
のコンポーネントのボックス化を解除しても意味がありません。書くことは完全に合理的ですが:
_data T = T {-# UNPACK #-}!Int
_
T
コンストラクターと_Int#
_コンポーネントを持つランタイムオブジェクトを生成します。 Int
で裸のnewtype
を取得するだけです。
参照: