もなもなMaybeモナド

http://d.hatena.ne.jp/ysano2005/20060412/1144843566
を読んで、確かにモナドの短めのサンプルコードがあると便利だよな、と思ったので、勉強がてら自分で書いてみることにした。http://www.sampou.org/haskell/a-a-monads/html/introII.htmlにそって一つずついこう。

今日はMaybeモナド(http://www.sampou.org/haskell/a-a-monads/html/maybemonad.html)。Maybeモナドは、Nathingかあるいは何かの値を含んだモナド。辞書を検索した返り値なんかに使う。結果がなければNothing、結果があればJust 値。

サンプルの説明

書いたサンプルは単純に、連想配列(sample_alist,sample_alist2)から対応する値を返すmylookup関数。返り値はMaybeモナド。ちなみに、同じ型を持つlookup関数は組込みで存在する。
ベタに再帰を手書きしたバージョンと、mplusを使ってモナドっぽく(?)書いたバージョン、さらにMaybeモナドはIOモナドとは違ってをモナドを外せるので外すバージョンも並べてある。

サンプルコード

import qualified Monad (mplus)
--importの書式は http://www.geocities.jp/shido_takafumi/hs/haskell11.html 参照

-- 検索する連想配列
sample_alist = [("a","A"),("b","B")]
sample_alist2 = zip (map show [1..]) [1..] -- 無限連想配列

-- 再帰べた書きバージョン
mylookup :: (Eq a) => a -> [(a,b)] -> Maybe b
mylookup key [] = Nothing
mylookup key ((tag,value):rest) =
    if tag == key then Just value else mylookup key rest

-- mplusバージョン
mylookup2 :: (Eq a) => a -> [(a,b)] -> Maybe b
-- foldlにすると無限リストの時戻ってこなくなる
mylookup2 key alist = foldr Monad.mplus Nothing (map pick alist)
    where pick (tag,value) = if tag == key then Just value else Nothing


-- Maybeは外せる (型が限定されちゃうけど)
mylookup3 :: (Num a, Eq b) => b -> [(b,a)] -> a
mylookup3 key alist = case (mylookup key alist) of
                      Just x -> x
                      Nothing -> 0

main = do
       print (mylookup "a" sample_alist)
       print (mylookup "b" sample_alist)
       print (mylookup "c" sample_alist)
       print (mylookup "10" sample_alist2)
       -- print (mylookup "a" sample_alist2) もどってきません
       print (mylookup "a" (take 1000 sample_alist2))
       print ""
       print (mylookup2 "a" sample_alist)
       print (mylookup2 "b" sample_alist)
       print (mylookup2 "c" sample_alist)
       print (mylookup2 "10" sample_alist2)
       print (mylookup2 "a" (take 1000 sample_alist2))
       print ""
       print (mylookup3 "10" sample_alist2)
       print (mylookup3 "a" (take 1000 sample_alist2))
{-
main実行時の出力
Just "A"
Just "B"
Nothing
Just 10
Nothing
""
Just "A"
Just "B"
Nothing
Just 10
Nothing
""
10
0
-}