ふつける:11章読んでる

読み終わってはいません.11章は,ふつけるの言葉を借りるのならば"Haskell最大の難関".C言語でのポインタ,Perlでのオブジェクト指向Pythonでのインデント,Rubyでのドキュメント作成*1みたいなもんですか.
Monadを理解する事で,Haskellerになれる事を信じて.


とりあえず少しずつ理解していくのが大事だと思う.えっと,まず,Monadには演算を繋ぐ,という目的があるのね.

Monadクラス

Monadクラスって何?クラス定義の中心は,これ,とのこと.

class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  return :: a -> m a

(>>=)*2はbindと読むそうです.なるほど,繋いでる感じなんだな.

正しいモナドであるためには,この2つのクラスメソッドを実装している必要があります.

正しいモナド・・・そこに愛はあるのか.僕たちは,正しいモナドでいられるのだろうか.

モナド

モナドの定義(なんだと思う).

Haskellにおいてモナドとは,Monadクラスのインスタンスであり,そのクラスメソッドの(>>=)とreturnを正しく実装し,モナド則を満たす型の事である.

モナド則とは?

  1. (return x) >>= f == f x
  2. m >>= return == m
  3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)

今はまだ理解しなくて良いのね.感じるぞ.・・・だめだ,感じれねい.

Maybeモナド

以前,lookupの動きを試していた時に,ボクはもうモナドに出会っていたのですね*3
Maybeは,モナドとして使った時に真価を発揮する.lookup関数を繰り返し使って検索する時に便利,とのこと.
ふつけるに書いてある事を,10周年にかこつけてエヴァっぽくすると,こうなる.


例えば,こういうタプルのリストがあるとする.

children = [ ("1st", [("name","Rei"),("evangelion","zero")]),
             ("2nd", [("name","Asuka"),("evangelion", "2nd"),("mother","Kyoko")]),
             ("3rd", [("name","Shinji"),("evangelion","1st"),("mother","Yui")]) ]

ここで,3rd childrenの母親(mother)の名前は?となると,

case (lookup "3rd" children) of
    Just entries -> lookup "mother" entries
    Nothing -> Nothing

とする事で得られる.まず"3rd"を検索し,次に"mother"を検索している.これを,

  1. まず"3rd"を検索し,次に"mother"を検索する
  2. ただし,はじめの検索が失敗したら次の検索はしなくてもよい

とできるのが,Maybeモナド
Maybeモナドとして使うと,さっきの式と同じ式が,たった一行でできる.簡単に書けるし,(意味さえ分かっていれば)読み易い.

lookup "3rd" children >>= lookup "mother"

(>>=)が出てきた.実際にやってみよう.

Main> lookup "1st" children >>= lookup "mother"
Nothing
Main> lookup "3rd" children >>= lookup "mother"
Just "Yui"
Main> lookup "4th" children >>= lookup "mother"
Nothing

return?

よくわからないreturn.同じように,ふつけるではreturnも使っているのだけども,その使い方はこんな感じのようだ.

(return children >>= lookup "2nd") >>= lookup "evangelion"

ふつけるにすげぇ分かり易い説明が書いてあるんだけど,return childrenはMaybe aで,lookup "2nd"はa -> Maybe aになり,結果括弧内はMaybe aになる.そんで,同じようにlookup "evengelion"はa -> Maybe aなので,式全体を通すと,Maybe aになる.
ここでもう一度,returnの型の定義を見よう.

return :: a -> m a

だ.returnのaにchildrenが当てはまり,Maybe aを返してる事になる.凄いな.


実際に型を確認すると,

Main> :t return children
return children :: Monad a => a [([Char],[([Char],[Char])])] -- このaはMaybeだと思えば良い

Main> :t lookup "2nd"
lookup "2nd" :: [([Char],a)] -> Maybe a

Main> :t (return children >>= lookup "2nd")
return children >>= lookup "2nd" :: Maybe [([Char],[Char])]

Main> :t lookup "evengelion"
lookup "evengelion" :: [([Char],a)] -> Maybe a

Main> :t (return children >>= lookup "2nd") >>= lookup "evangelion"
return children >>= lookup "2nd" >>= lookup "evangelion" :: Maybe [Char]

なるほどなぁ.


ここでもう一度,(>>=)を思い出そう.(>>=)の型の定義は,

(>>=) :: m a -> (a -> m a) -> m b

だ.Maybe aが左辺にあって,a -> Maybe aがまさに右辺にあり,Maybe bが返ってるではないか!
つ,つぎはリストモナドね.

*1:ソースコードがドキュメントだ、バグも全て記述されて いる,とは誰が言ったのでしょうか.

*2:う,うちゅうご

*3:IOを除く