Haskell超初心者勉強会20
第14章 後半
2013/9/9
Sunday, September 8, 13
今日の内容
•Maybe モナドで電卓を安全にする
•モナディック関数の合成
•新しいモナドを作る
Sunday, September 8, 13
これまでの電卓
•方針: Maybe を使って、失敗を正しく扱う
solveRPN :: String -> Double
solveRPN = head . foldl foldingFunction [] . words
foldingFunction :: [Double] -> String -> [Double]
foldingFunction (x:y:ys) "*" = (y * x):ys
foldingFunction (x:y:ys) "+" = (y + x):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
キケン!!
http://ideone.com/FNWy4l
Sunday, September 8, 13
reads (用意されている)
•読み取りに成功した時、[(読み取り結
果, 消費しきれなかった文字列)]
•読み込み失敗時は空リスト
> reads "123" :: [(Double, String)]
[(123.0,"")]
> reads "123abc" :: [(Double, String)]
[(123.0,"abc")]
> reads "abc" :: [(Double, String)]
[]
Sunday, September 8, 13
readMaybe
•全部読めたら Just
•それ以外は Nothing
readMaybe :: (Read a) => String -> Maybe a
readMaybe st = case reads st of [(x, "")] -> Just x
_ -> Nothing
Sunday, September 8, 13
畳み込み関数
•Maybe [Double] を返すモナディック
関数に変更する
foldingFunction :: [Double] -> String -> Maybe [Double]
foldingFunction (x:y:ys) "*" = return $ (y * x):ys
foldingFunction (x:y:ys) "+" = return $ (y + x):ys
foldingFunction (x:y:ys) "-" = return $ (y - x):ys
foldingFunction xs numberString =
liftM (:xs) (readMaybe numberString)
Sunday, September 8, 13
安全な solveRPN
•bind するときに pattern match
•pattern match に失敗すると Nothing
solveRPN :: String -> Maybe Double
solveRPN st = do
[result] <- foldM foldingFunction [] (words st)
return result
http://ideone.com/BiVXC4
Sunday, September 8, 13
モナディック関数の合成
<=<
-- ただの関数合成 .
f = (+1) . (*100)
-- モナディック関数の合成 <=<
-- テキストでは型宣言が無いが、型宣言が無いとコンパイルエラーになる。
g :: (Monad m, Num a) => a -> m a
g = (x -> return (x + 1)) <=< (x -> return (x * 100))
Sunday, September 8, 13
. → >=>
id → return
-- これはただの関数合成
f' = foldr (.) id [(+8),(*100),(+1)]
•ナイトが3手で行けるかを確認する関数
canReachIn3 を
関数合成でn手に一般化します。
•コード参照 http://ideone.com/l1GXEu
Sunday, September 8, 13
モナドを作る
•確率付きの値を表す Prob a
•確率部は Rational で表す
•1%2 → 1/2の確率
•[(3,1%2),(5,1%4),(9,1%4)] など
Sunday, September 8, 13
Prob newtype宣言
newtype Prob a =
Prob { getProb :: [(a, Rational)] }
deriving Show
Sunday, September 8, 13
Prob は Functor?
•List が Functor だから Prob もきっと
Functor
•値に作用させる
•確率はそのまま
instance Functor Prob where
fmap f (Prob xs) = Prob $ map ((x, p) -> (f x, p)) xs
Sunday, September 8, 13
Prob は Monad?
return
•値がきたら、確率 1 の Prob にすれば
いいのでは。
return x = Prob [(x, 1%1)]
Sunday, September 8, 13
Prob は Monad?
>=>
• m >>= f は常に join (fmap f m) と等価
• join :: Prob (Prob a) -> Prob a
から考えて、それを使って >>= を定義
Sunday, September 8, 13
flatten (join)
•外側の確率と内側の確率を掛ける
flatten :: Prob (Prob a) -> Prob a
flatten (Prob xs) = Prob $ concat $ map multAll xs
where multAll (Prob innerxs, p) =
map ((x, r) -> (x, p*r)) innerxs
Sunday, September 8, 13
Prod as Monad
•モナド則を満たしていることを確認
instance Monad Prob where
-- 文脈に入れるときは、必ずそれが起こる (=生起確率 1) で入れる。
return x = Prob [(x, 1%1)]
-- m >>= f は join (fmap f m)
m >>= f = flatten (fmap f m)
-- パターンマッチに失敗したら
fail _ = Prob []
Sunday, September 8, 13
イカサマコインを
投げる例
•コード参照 http://ideone.com/6FPW8M
Sunday, September 8, 13
Monadが出来るまで
•ある問題のある側面をモデル化した型
•あれ?もしや Monad?(気付き)
•Monad instance を与える
Sunday, September 8, 13
やっと14章おわったーー!
Sunday, September 8, 13

Haskell超初心者勉強会20