LoginSignup
9
6

More than 5 years have passed since last update.

`newtype` キーワードに関して勉強したことの整理

Last updated at Posted at 2015-03-17

学習の素材は、
すごいHaskellたのしく学ぼう!

この表記は、私見・感想です。

newtype キーワードと似たようなキーワードとの比較

newtype

newtype キーワード は既存の型を包んで新しい型を作るためのもの。値コンストラクタ、フィールドがそれぞれ一つだけ用意されている。後述するようなインスタンスを作るために使用することがある。
newtype で型を包むと(ほどくと)、data と違ってオーバーヘッドがかからない点がメリット。

data

data キーワード は自作の新しいデータ型を作るためにある。値コンストラクタもフィールドも複数用意できる。 オリジナルの型を作る!ということなら、このキーワードが適切。

type

型シノニムを作るために type キーワードを用いる。既存の型に別名をつけて、プログラムを整理しやすくする。その型をどういう目的で使っているのか、コードを読む人に伝えられる。

たとえば、Int を特定の文脈に合わせて Books と読んでみたり。

newtype を使って型クラスのインスタンスを作る

ある型を型クラスのインスタンスにしたいをのだが、型引数が一致しなくてできないということがある。たとえば、タプル (,) :: a -> b -> (a, b)Functor のインスタンスにして、fmap の引数でとる関数を fst に適用したいというようなケース。

((,) a) をインスタンスにすることは簡単にできるが、これだと関数適用できるのは snd の方になってしまう。

このような時に newtype で新しい型を作り、要求を満たすことができる。

newtype Pair b a = Pair { getPair :: (a, b)} deriving (Show)

instance Functor (Pair c) where
    fmap f (Pair (x, y)) = Pair (f x, y)

型引数の順序が反転しているため、固定されているのが snd の型になっていることがわかる。パターンマッチも使えるので、pair 型からタプルを取り出して、fst 側に関数適用できている。
また、getPair により、タプルに変換することも簡単に行える。

内部的にはタプルを使うが、型引数の順番だけ工夫して新しい型を作り、型クラスのインスタンスに対応させている。そういうニーズで、newtype が使える。

newtype と遅延評価

newtype で新しい型を作ると、必ずコンストラクタが一つ、フィールドが一つとなる ことが明らかなので、 パターンマッチにおいて引数を評価しなくてもその型であると判定できる。そのため、ある関数が newtype で作られた型を引数に取るとき、それがundefined だとしても結果がエラーとならない場合がある。 Haskell は本当に必要になるまで評価を遅らせる性質があり、ここでもその性質が現れている。

newtype CoolBool = CoolBool {getCoolBool :: String}
helloMe :: CoolBool -> String
helloMe (CoolBool _) = "hello"

この例では、GCHi で次のように書いても、結果を得られる。

*Main> helloMe undefined 
"hello"

undefined :: a は任意の型として取り扱うことができる。そして、評価するとエラーになるという特徴がある。つまり、このコードに undefined を埋め込むと、通常、コンパイルは通るものの実行する(ために評価する)とエラーを出す。上のケースではコンパイルが通り、かつ遅延評価なので評価されずに(エラーが出ないので)正常終了するということである。

9
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6