みどりねこ日記

よくわからないけど、頑張りますよ。

Haskellのモナド(7)

前回までの説明で、おそらく>>=演算子とreturnが、Maybeを使ったコードを書くときに、煩雑なコードから解放されるために有益であると同意してもらえると思います。これがどうして動くのか、そしてこれが何を意味しているのかを考えましょう。

その説明のために、以下の様なコードを書きました。

bothGrandfathers p = do {
	f <- father p;
	gf <- father f;
	m <- mother p;
	gm <- father m;
	return (gf, gm);
}

このコードが命令型言語のコードの断片に見えたとしたら、それは正しいです。とりわけ、この命令型言語は例外処理をサポートしています。例えば、もし例外が起きたら、doブロック全体が失敗し、例外として終了します。

言い換えれば、father pという式は、Maybe Personという型をもちますが、Person型を結果として返す命令型言語の式として翻訳されます。これはすべてのモナドにおいて行われます。M a型の値はa型を返す値として翻訳されるということです。そしてこれらはモナドMを拾って文脈から類推されます。

(>>=)演算子はセミコロンの関数版です。let式が、

let (x = foo) bar	<===>	(¥x -> bar) foo

のように関数で表せるように、変数宣言とセミコロンは>>=演算子として表すことが出来ます。

x <- foo; bar	<===>	foo >>= (¥x -> bar)

関数returnはaという値をM aという命令型言語のレベルにまで持ち上げます。

異なる意味をもつものはそれぞれ異なるモナドに対応します。

意味 モナド
例外(匿名) Maybe
例外(エラー情報付き) Error
状態 State
入出力 IO
非決定性 [](リスト)
環境 Reader
ログ Writer

更にいうと、それぞれは単独で実行されることより、複数の異なるものと一緒に利用されることが多いです。そのため、モナドトランスフォーマが必要となります。

モナディックパーサコンビネータのようなモナドのいくつかは、命令型言語との対応をなくしてしまっています。