Haskellのnewtype
代数的データ型を用いて新たな型を定義する
元の型とは全くの別物になる
パフォーマンスに影響を与えない
コンストラクタに包んだり出したりするオーバヘッドがかからない
code:ghci(hs)
ghci> newtype N = N Int
ghci> let n = N (1+1)
ghci> :sprint n
n = _
ghci> seq n ()
()
ghci> :sprint n
n = N 2
そのため!を使った定義はできない
(元々なっているので)
再帰的定義もできる
code:例.hs
newtype Fix f = Fix (f (Fix f))
制限がある
値コンストラクタは1つだけ
code:hs
newtype Volume = Volume Double -- ok
newtype A = B String | C Int -- ng
その値コンストラクタが持てるフィールドも1つだけ
code:hs
newtype Size = Size { unSize :: Int } -- ok
newtype Point = Point -- ng
{ pointX :: Int
, pointY :: Int
}
newtypeは1つしか値コンストラクタを取らない
そのため、パターンマッチにおけるパターンは1つしかない
このルールは、ランタイムでtypeと同じ挙動をさせるために必要
このルールによって、dataと少し異なる挙動をすることがある
例えば以下の様なコード
dataとnewtypeを使って同じ様な構造の型と関数を定義する
code:hs
data D a = D a
f (D _) = "hello"
newtype N a = N a
g (N _) = "hello"
これらの関数をundefinedに適用する
code:hs
f undefined -- error
g undefined -- "hello"
newtypeの定義は、ランタイム上で見れば、以下の様に定義しているのと同じ
code:hs
type N a = a
g _ = "hello"
だからerrorにならない
derivingで型クラスのインスタンスにするときは、中身の既存の型がその型クラスのインスタンスである必要がある
code:hs
newtype ZipList a = ZipList { getZipList :: a } -- こう使える
getZipList $ ZipList "hoge"
すごいH本.icon p.261
参考
typeより、エラーメッセージがわかりやすくなる ref