fugafuga.write

日々のログ

すごいH本 part78

newtype と 遅延評価

undefined という値がある。これは、ぶっ壊れた計算を表す。 この値を評価すると Haskell はすごく怒る。

*Main> undefined
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
  undefined, called at <interactive>:14:1 in interactive:Ghci3

すなわち例外を投げる。

しかし、undefined を含むリストを作っても、undefined の要素を要求しなければ、 例外発生せずに処理される。

*Main> head [3,4,5,undefined,2,undefined]
3

Haskell は先頭要素以外を評価しないためである。

ここで以下のような型を作る

data CoolBool = CoolBool { getCoolBool :: Bool }

中身の Bool が True か False かどうかによらず、'hello' を返す関数を書く。

helloMe :: CoolBool -> String
helloMe (CoolBool _) = "hello"

この関数を、CoolBool 値ではなく undefined に適用してみる。

*Main> helloMe undefined
"*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
  undefined, called at <interactive>:21:9 in interactive:Ghci1

data キーワードで定義された方には複数の値コンストラクタがあるかもしれないので、 関数の引数が (CoolBool _) に合致するかどうかを確認するためには、 どのコンストラクタが使われたのか分かるところまで引数の評価を進める必要がある。

そして、undefined を評価しようとして例外が発生している。

今度は、CoolBool を newtype で定義する。

newtype CoolBool = CoolBool { getCoolBool :: Bool }

同じように関数を適用してみる

*Main> helloMe undefined
"hello"

例外が発生しない。

newtype キーワードはコンストラクタを1つしか作れないことを Haskell は知っているため、 引数が (CoolBool _) パターンに合致すると判定できる。

  • data はオリジナルな型を無から作り出すもの
  • newtype は既存の型をもとにはっきり区別される新しい型を作るもの
  • data に対するパターンマッチは箱から中身を取り出す操作
  • newtype に対するパターンマッチはある型を別の型に直接変換する操作

type vs. newtype vs. data

type

型シノニムを作るためのもの

type IntList = [Int]

型注釈にどちらの名前を使うかは自由

*Main> ([1,2,3] :: IntList) ++ ([1,2,3] :: [Int])
[1,2,3,1,2,3]

型シノニムは型シグネチャを整理してわかりやすくしたい時に使う。 [(String, String)]PhoneBook という名前で扱えるようにするなど。

newtype

既存の型を包んで新しい型を作るためのもの

newtype CharList = CharList { getCharList :: [Char] }

この場合、CharList[Char]++ で連結することはできない。 ++ はリスト限定の演算子なので無理。

newtype 宣言でレコード構文を使うと、newtype の値コンストラクタと、 フィールド内の値を取り出す関数が作られる。

新しい型は、元の型の所属していた型クラスを引き継がないので、deriving で導出するか、 インスタンス宣言を手書きするか、GeneralizedNewtypeDeriving を使う必要がある。

data

data は自作の新しいデータ型を作るためのもの。

3つの使い分け方

  • 型宣言を整理したい、型名が体を表すようにしたいだけなら type
  • 既存の型をある型クラスのインスタンスにしたくて、新しい型にくるむなら newtype
  • まったく新しいものを作るなら data

所感

3つのデータ型宣言の違いがなんとなくわかった。

モノイドはいまだ登場せず。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る