すごいHaskell七章後半(7.4〜7.6まで)

自分が疑問に思ったり、理解できなかったところを埋めるために書いてたのが、いつのまにか本のコピペになってたので軌道修正したい。

型コンストラクタと値コンストラク

 3次元ベクトル型 Vector

data Vector a = Vector a a a deriving (Show)

 の、

Vector a

 が型コンストラクタ。

Vector a a a

 が値コンストラクタ。
 型を書くべきところ(関数の型シグネチャとか)では型コンストラクタを書き、値が必要になるところ(変数へのバインディング、関数定義・呼び出しとか)では値コンストラクタを書く。


 ここの Vector は、1つの型の値しか取れなくなってるけど、 Int と Double を混在させるとかはできないのかな。関数も同じ型同士でしか計算出来ないし。多分後で何とかする方法が出てくるだろう。

何月でもいいよ

 代数データ型で列挙型を作ろうの巻。
本の例が曜日だったので、月を定義してみることにした。

data Month = January | February | March | April | May | June | July |
             August | September | October | Novenmber | December
	      deriving (Eq, Ord, Show, Read, Bounded, Enum)

 Bounded と Enumインスタンスなので、 minBound, maxBound とレンジを組み合わせてリストを作れるっていうのが面白かった。

ghci> [minBound .. maxBound] :: [Month]
[January,February,March,April,May,June,July,August,September,October,Novenmber,December]


 この節でちょっと疑問だったのが、「代数データ型」っていう用語の定義。索引を見ると、もう少しあと(139p)で出てくるっぽい。 data を使って定義した型みたいな感じでいいのかな。型が値コンストラクタを持っているような型?


もう一個用語が出てきた。

  • 値コンストラクタがゼロ引数 = フィールドを持っていない

そういえば、ここでの月の名前(JanuaryとかApirlとか)って値コンストラクタなんだよな。値コンストラクタをそのまま値として使える。

型シノニム

 既存の型に別名を与える。型シノニムは型同義名ともいうらしい。
こう定義することで

type PhoneNumber = String
type Name = String
type PhoneBook = [(Name, PhoneNumber)]


こう書いてたのが

type PhoneBook = [(String, String)]
inPhoenBook :: String -> String -> [(String, String)]  -> Bool
inPhoenBook name pnumber pbook = (name, pnumber) `elem` pbook


こうなる。

inPhoenBook :: Name -> PhoneNumber -> PhoneBook -> Bool
inPhoenBook name pnumber pbook = (name, pnumber) `elem` pbook


 引数とかの意味が、型名を見ただけでわかる。名前重要の考え方っぽい。
ただし、見覚えのない型が出てくるたびに定義を探さないといけないので、闇雲に使えばいいものでもない。型の定義を見ないといけないのは代数データ型も同じだけど、型シノニムは必ず使わないといけないものでもないので。
 結構使われてそうだけど、実際のコードだとどのくらい使われてるんだろう。

関数の成功と失敗を表す Either 型

data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show)

返り値を Eitherなにがしa なにがしb 型にして成功したら Rightなにがしb を、失敗したら Left なにがしa を返す。
Maybe との違いは、関数の失敗(Maybe だと Nothing に相当)の際に、何かしらの値を返せるところ。 Left String にしておけばエラーメッセージが返せる。

関数がなぜ失敗したのか、どのように失敗したのかを知りたいとき、普通は Either a b 型の返り値を使います。 (134p)

ってあるから、普通は Either を使うんだろうな。try-catch みたいな感じ?あまりオブジェクト指向と関連付けて考えないほうがいいかもしれない。
実際 Left a が返って失敗したっていうのは分かるな。