モナドのこと

kazu-yamamotoさんのhttp://d.hatena.ne.jp/kazu-yamamoto/20080208/1202456329に勝手に刺激されて、はてなダイアリーはじめました。
これまでHaskellを勉強してきて、自分なりのモナドの理解をまとめようと思って…最初はkazuさんのブログにコメントを長々とつけてしまった…


以下コメントのコピー


更なる混乱を招くだけかもしれませんが、僕なりのモナドについての理解を話させていただきたいと思います。本来なら自分のブログで展開するべきなのでしょうが、ブログをまだ持っていないので、迷惑だとはおもいますが寄生させていただきます。


まず、参照透過性との関係。Haskellでは関数呼び出しは返り値が必要になるまで実行されないわけなんですが、だからといって、コードを書く側が呼び出しのタイミングをまったく制御できないかというと、そうゆうわけでもなくて、要するに関数を実行したいときに、帰り値が必ず必要になるようにすればよい、と。


例を挙げれば、

  lst a = repeat a -- aが無限に続くリストを返す。
  main = putStrLn $ head $ lst 1

参照透過性が保障されているので、headとしては、(lst 1)を受け取ろうが、[1, 1, …] を受けとろうが外見上の違いはまったくない。そしてHaskellでは規約として、headには(lst 1)がわたるようになっているわけですね。それでもって、headの中で初めてlst 1の帰り値が必要な状況になる。つまりここでもってlst 1が実行されるわけですね。つまり、このリストから値を取り出すという動作がリストを返す関数を評価させるきっかけになっている。(細かい話を言えば、headが評価されるタイミングはputStrLnに(head $ lst 1)が渡った後ですね...)


 Haskellの解説を読んでみるとわかるのですが、実はリストもIOと同じモナドなわけです。リストは複数の同型の値を収納できるリンクリストなわけですが、IOは「外界」という器から値を取り出すことができる「しくみ」という風にも見て取れると思うのです。本でもいわれているように、IO型はアクションであるともいえるわけですが、これはやはり、IOモナドの中でも参照透過性を保障しているために、値を返す関数と返す値との違いがまったくわからないという状況になっているのだと理解しています。


 最後に>>=なのですが、これは実は単なる中置関数で、その型は

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

となっていて、一つ目の引数は m a (何かの容器に入ったa型の値)、
2つ目の引数は a型の値をもらって,何かの容器に入ったb型の値を返す関数で、
その帰り値は何かの容器に入ったb型の値なわけです。つまり、>>=の定義として、第一引数m aからaを引き出すぞと宣言しているわけですね。つまりこれはmがIOだろうと、Maybeだろうとリストだろうと、>>=に渡った時点で必ず評価・実行されるということになる、と…


 つまり、モナドは参照透過性を崩さずに実行順序の制約を導入したというところがすごいところということなんでしょう...ほかにもあるのでしょうが...


 僕がまだわからないのはなぜモナドという名前なのか、モノイドとの関係は何なのかというところです...ご存知でしたら教えてください…
何かの足しにしていただければ幸いです。何分独学ですので、間違っているところがありましたら指摘してください。(ってひとんちでやるなって感じですね...)


ということで、もう自分ちなので、がんがん突っ込んでやってください。