Maybe モナドのプログラミング

モナドについていろいろ抽象的に考えてもプログラムは書けないので、モナドのデータ型の中で一番わかりやすそうな Maybe モナドを使ったプログラムをつくってみた。

ます、Maybe モナドがどんなものかを知るために、Maybe モナドを戻り値に戻す lookup 関数の動作を見てみる。lookup 関数は、第1引数の値が、第2引数のタプルのリストの中のタプルの第1要素と一致すれば、そのタプルの第2要素を Just x の形で返し、一致が見られなかった場合は、Nothing をかえす。文章で表すより使ってみた方が早いので、以下に示す。

Hugs> lookup 1 [(1,2),(3,4)]
Just 2
Hugs> lookup 0 [(1,2),(3,4)]
Nothing

そこで、このような Maybe モナドがどのように定義されているのか見てみる。

Hugs のコマンドプロンプトで次のように入力すると、

Hugs> :find Maybe

エディターに、Prelude の内容が表示されるはずだ。そこで、maybe を検索していくと次のような記述を見つけることができる。

-- Maybe type ---------------------------------------------------------------

data Maybe a = Nothing | Just a
deriving (Eq, Ord, Read, Show)

maybe :: b -> (a -> b) -> Maybe a -> b
maybe n f Nothing = n
maybe n f (Just x) = f x

instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)

instance Monad Maybe where
Just x >>= k = k x
Nothing >>= k = Nothing
return = Just
fail s = Nothing

第1段落を見ると、Maybe のデータ型が、Nothing と Just x であることが分かる。第4段落には bind 演算子 >>= の定義がある。これを見ると、Just x が >>= をはさんで 関数 k に渡されたときは、k x が実行され、Nothing が k に渡されると、Nothing が返されることがわかる。Nothing が渡されると k がどんな関数でも Nothing が返えるので、実質的には Just x が関数 k に渡されたときだけを考えてプログラムすればよい。

そこで、lookup の戻り値である Maybe モナドを受け取って、Maybe モナドがたのデータを返す testmaybe 関数をプログラムしてみる。testmaybe 関数が Maybe モナドを受け取ると言っても、>>= の定義を見ると関数 k には Just のデータ部分の x が渡っているので、testmaybe の型は、Int -> Maybe Int の形にすることになる。Just x から x を受け取った testmaybe が x を2倍して Just n の形で返すようにするには、次のようにプログラムする。

Hugs> :e testmaybe.hs

(testmaybe.hs の内容)
testmaybe :: Int -> Maybe Int
testmaybe x = return (x * 2)

それでは、こうして作った Maybe モナドの世界の新しい住人 testmaybe を動かしてみよう。

Hugs> :l testmaybe.hs

まず、単純に Just 1 という Maybe モナドのデータを testmaybe に渡してみる。
Main> Just 1 >>= testmaybe
Just 2
Just 1 のデータが Just 2 になって帰ってきているのでうまくいったようだ。それでは Nothing ではどうだろう。

Main> Nothing >>= testmaybe
Nothing

ちゃんと Nothing が返ってくる。それでは、lookup の戻り値を受けて見よう。
Main> lookup 1 [(1,2)] >>= testmaybe
Just 4

また、testmaybe の戻り値を次々に testmaybe につなげていくこともできる。
Main> testmaybe 1 >>= testmaybe
Just 4
Main> testmaybe 1 >>= testmaybe >>= testmaybe
Just 8

このように、モナドの理論は難しいが、モナドの世界の住人を増やすのは意外に簡単だった。

モナドの世界でプログラミングをする限りは、関数がモナドの外の世界に影響することはないのでモジュール化されたプログラムを気楽に作ることができる。また、関数と関数を結び付ける bind 演算子 (>>=) のおかげで、要素的な働きをする関数を定義しておくと、複雑な処理も関数の結合だけで実現できてしまう。たとえば Maybe モナドの場合、データの取得が失敗した場合の if then else 制御文による記述を個々のプログラムで行う必要がなくなるのですっきりした処理の記述になる。

IO処理のために仕方なくモナドの世界のプログラムをするのではなく、積極的にモナドのプログラムを活用すると便利なのかもしれない。もちろん、もう少し Haskell が分かってからの将来の話になるが。
[PR]
by tnomura9 | 2009-08-29 07:56 | Haskell | Comments(0)
<< やさしい Haskell 入門 モナドとの付き合い方。 >>