もなもな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 -}