モナド

まだ完全には消化できていないので、とりあえず思ったことだけつらつらと。

モナドの前に、まずは型クラスをちゃんと理解しよう

EqとかOrdみたいな単純なものは、それ自体がデータとしての意味をもつ型を対象にした型クラスだけれど、Monadは「型パラメータをもつ高階の型」を対象にした型クラス。このギャップがかなりでかい。よく噛んでから飲み込もう。

個々の具体例から使い方を覚えよう

フツーの人はモナドを最初からトップダウンで理解しようとしない方が良い。 MaybeモナドとかListモナドとかStateモナドとかをいろいろ触ってみてやっと「繋ぐ」というモナドの中核にある概念が少しずつ見えてくる。いきなりモナド則からとっかかると死ねる。これだけ見ても「何がやりたいの?」としか言えない。

モナドのイメージ

ある値があって、それを抽象的なふわふわした皮で包み込むことを考える。この時、裸の値を包み込むギミックがreturnであり、皮を引き剥がして中の値を取り出し別の関数に渡すのが bind(>>=) である。この、値を別の関数に渡すタイミングで、舞台裏でゴニョゴニョといろんな処理が動いているんだけど、そこで何を行うかは各モナドで多種多様。
bind を使うことで、「値を喰って皮に包み込まれた状態のものを吐く演算」をたくさん繋ぐことができる。で、その「繋ぎ方」を規定しているのがモナドの各インスタンス型であり、「繋ぎ方を決めるルールに課されたメタルール」がモナド則。

とりあえずそんなイメージでいいような。たいへん柔軟な仕組みで、実際に値を持ってる必要は無いし、リストみたいに値を複数持ち、bindした関数を複数回呼び出したりもできるし、逆に全く使わなくてもいい。型とモナド則を満たす限り何をしても自由。「柔軟だ」というのは得てして「抽象的だ」ということ。頭働かせー。

とりあえず bind の挙動を理解して、既存のモナドをまがりなりにも使えるようになれば最初の山は越えたっぽい。自分でオリジナルのモナドを定義するとかいうのは、そこからさらにずっと先の次元のお話。

メソッドチェーン

OO脳には、「メソッドチェーン的なもの」という類推が理解しやすいかもしれない。*1

obj >>= f >>= g >>= h

obj.bind(f).bind(g).bind(h)

と読んでみる。最初の bind は self (IO Foo 型) と f (Foo -> IO Bar 型)を使って、IO Bar 型の値を作る。これを新たな self として、次のbindは self(IO Bar 型) と g (Bar -> IO Baz 型)を使って、IO Baz 型の値を作る。こんな感じで、メソッドチェーンを通して型が IO Foo -> IO Bar -> IO Baz -> IO Hoge と変わっていくのだけど、型は「IO a」という形で一貫していて、メソッドチェーンで使われる bind も「IOモナドの bind」で一貫している。
だめだ、ぐだぐだな説明にしかならん…。結合性も右からだしなぁ。…いつかまとめます。

*1:かえって混乱するかもしれない