Yet Another Haskell Tutorial 23

8.1 Do Notation (続き)

Do 記法をモナド演算の記法に翻訳するときのルールは4つある。それは、次のようなものだ。

1. do {e} -> e
2. do {e; es} -> e >> do {es}
3. do {let decls; es} -> let decls in do {es}
4. do {p <- e; es} -> let ok p = do {es}; ok _ = fail "..." in e >>= ok

注意しなくてはならないのは、上のルールは再帰的定義になっていて全体で do 記法をモナド演算に変換するための文法規則になっている。上のルールで e は do 記法の先頭の1個のアクションを表し、es は do 記法で記述された残りの一連のアクションを表している。

8.1.1 Translation Rule 1

最初のルール do {e} -> e は単独のアクションでは do キーワードはあってもなくてもよいことを示している。これは本質的に、do 記法の再帰的定義の base case だ。Base case は一個だけのアクションに適用される。他の3つのルールは複数のアクションに適用される。

8.1.2 Translation Rule 2

2番目のルールは、do {e; es} -> e >> do {es} だ。Do 記法の先頭にアクションがあり、その後にアクションのリストが続いている場合のルールだ。このような場合は以前に述べた >> 関数を使う(注:>> の定義は、a >> x = a >>= \_ -> x だから左項からの戻値は読み捨てられる)。この場合は do {e; es} は先頭のアクション e を実行し、その結果を読み捨てて、次のアクションのリストについて do {es} を実行する。

たとえば do {putStrln "hello"; es} の場合は、端末に "hello" が印字され、その後 do {es} の処理が続く。

8.1.3 Translation Rule 3

3番目のルールでは、do {let decls; es} を let decls in do {es} に翻訳する。このルールは do 記法の中の let キーワードを処理するためのものだ。let キーワードの中の宣言文を、in キーワードによって do {es} に対して有効にする。

8.1.4 Translation Rule 4

このルールは do {p <- e; es} を let ok p = do {es}; ok _ = fail "..." in e >>= ok に翻訳する。この翻訳は少々わかりにくいが、おおまかに言うと do {p <- e; es} を e >>= \p -> es に翻訳するのと同じ意味を持つている。この解釈はより分かりやすい。つまり、e を実行してその結果に p という名前をつけ、その結果を es に送るのだ。

最初のルールが複雑なのは p が変数でなくても良いからだ。もっと複雑なパターンの場合も想定してある。例えば、次のようなコードは有効だ。

Prelude> let foo = do ('a':'b':'c':x:xs) <- getLine; putStrLn (x:xs)
Prelude> foo
abcYoBaby
YoBaby

このコードでは getLine アクションの結果が、先頭が "abc" でその後に文字列が続くパターンを想定している。しかし、問題はこのパターンマッチが失敗したときはどうなるかということだ。さいわい Monad (タイプ)クラスには fail 関数があるのでエラーメッセージを表示するのに利用することができる。パターンマッチのエラー処理がなければ、複雑な方の翻訳ルールは、単純な方の翻訳ルールと同じだ。

ちなみに上のパターンマッチが失敗した時の結果を次に示す。

Prelude> foo
acbYoBaby
*** Exception: user error (Pattern match failure in do expression at :3:14-31)

どうやら、上の1~4のルールは単なるバラバラなルールではなくて、do 記法をモナドの演算に翻訳するための構文解析の文法になっているようだ。これを見ても、do 記法がモナド演算の単なるシンタックス・シュガーであることが分かる。

また、Monad 演算と言っても特殊なデータ構造という訳ではなく、単に Monad (タイプ) クラスの多層関数や演算子を使った計算でしかない。自分で適当に作ったデータ型でも、Monad (タイプ)クラスのインスタンスとして宣言してそれらの多相関数を実装すれば、IO モナドなどと同じようなモナド演算を行う事ができる。ブラックボックスは意外に少ないのだ。

Yet Another Haskell Tutorial 24 へ続く ...
[PR]
by tnomura9 | 2013-03-06 21:40 | Haskell | Comments(0)
<< つかさ と さやにゃん Yet Another Has... >>