すごいHaskellたのしく学んでみる-その9
今回のテーマは、、、
- newtypeとdata
以上のテーマで、参ります。
newtypeとdata
「1つの型を取り、何かにくるんで別の型にみせかける」
というような事がしたい場合、
dataではなく、newtypeキーワードを使う事ができます。
例えば、このような場合
Prelude> data MyList a = MyList { getList::[a] }
これは以下のように書き換えられます。
Prelude> newtype MyList a = MyList { getList::[a] }
こう書くと、何が嬉しいんでしょうか??
dataとnewtypeの違いを見ていきたいと思います。
newtypeの方が高速
型をくるむのにdataキーワードを使うと、
コンストラクタに包んだり、ほどいたりする度にオーバーヘッドがかかります。
しかし、newtypeはそもそも、それ用のキーワードなので、
「内部処理は同じままに、違う型にしたいだけ」
という事をHaskellは、知っている為、
型推論を済ませた後、包んだりほどいたりの処理を最適化してくれるそうです。
じゃあ全部newtypeにすればよいのでは??
それはできません。
newtypeには
「コンストラクタは1種類、持てる値は1つだけ」
という制約があります。
(何かをラッピングする為だけに使うのですから、当然ですね)
newtypeで作った型のインスタンスの自動導出
newtypeでもderivingキーワードが使えます。
ただし、newtypeで包もうとしている中身の型が、
自動導出したい型クラスのインスタンスである必要があります。
Prelude> newtype MyList a = MyList { getList::[a] } deriving(Show)
newtypeと遅延評価
これは興味深い項です。
Haskellは、デフォルトで遅延評価な言語ですが、
dataとnewtypeでパターンマッチ時の評価が違います。
例えば、このような場合。
data Hoge = Hoge { getInt::Int } hoge :: Hoge -> String hoge (Hoge _) = "hoge"
Hogeの値をもらって、問答無用で「hoge」を返す関数を書いてみました。
このhoge関数にundefined(ぶっ壊れた計算を表すもの)を渡すと、エラーになります。
やってみましょう。
Main> hoge $ Hoge 1 "hoge" Main> hoge $ Hoge 10 "hoge" Main> hoge undefined "*** Exception: Prelude.undefined ← ※エラー
これは、dataキーワードで定義された型である為です。
dataキーワードで定義された型には、コンストラクタが何個かある可能性がある為、
引数が「(Hoge _)」に一致するかどうかを検証する為に、
どのコンストラクタが使われたのか、という事がわかる所まで、
引数を評価する必要があります。
ここで、undefinedが評価され、ブッブーとなるわけです。
では、newtypeはどうでしょうか。
newtypeはコンストラクタは絶対に一つしかありません。
先ほどの型をnewtypeに書き換えて試してみます。
newtype Hoge = Hoge { getInt::Int }
*Main> hoge undefined "hoge"
「hoge」が取得できました。
undefinedが評価されなかったということですね。
これはとても重要な違いだと思います。
- data : オリジナルな型を1から作り出す
- newtype : 既存の型を元に、別の新し型を作り出す
ここまでやってきて思いましたが。
newtypeを使う場面が、今のところ想像できません。
と書かれていますが。
その後の例を見ても、いまいちピンと来ない。
うーん、なんか良い例が無いものか、、、
単純に
「コンストラクタ1種類しかなくて、値1つしか持ってないdataがあったら、newtypeの方がはえーよ」
ってことなんでしょうか??
次回はMonoidとMonadをやって、最終回にしたいと思います。