『入門Haskell』練習問題例解(14)

p.128。モナド関連の関数です。

1. sequence_ を foldr を使って定義しなさい。
2. mapM と mapM_ を定義しなさい(sequenceなどを使ってもよい)。
3. foldM と foldM_ を定義しなさい。

sequence_
mySequence_ :: Monad m => [m a] -> m ()
mySequence_ = foldr (>>) (return ())

こうなります。ちなみに、sequence を foldr を使って定義すると

mySequence :: (Monad m) => [m a] -> m [a]
mySequence = foldr ((flip (.) (((flip (.) ((return .) . (:))) . (>>=)))) . (>>=)) (return [])

となります。もはや何がなんだか…

mapM, mapM_
mapM f = (\x -> sequence (map f x))
=> (\x -> sequence ((map f) x))
=> (sequence . (map f))
=> (\x -> sequence . (map x)) f
=> ((sequence .) . map) f

なので、最終的には

myMapM :: Monad m => (a -> m b) -> [a] -> m [b]
myMapM = (sequence .) . map

myMapM_ :: Monad m => (a -> m b) -> [a] -> m ()
myMapM_ = (sequence_ .) . map

となります。

foldM, foldM_

foldM f a [x1, x2, ... ,xn] は

f a x1 >>= (\y -> f y x2) >>= ... >>= (\y -> f y xn) >>= (\y -> f y [])

と同じことです。flip関数を使ってyが消去できるので、答えは

myFoldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
myFoldM f a [] = return a
myFoldM f a (x:xs) = (f a x) >>= (flip (myFoldM f) xs)

myFoldM_ :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m ()
myFoldM_ f a [] = return ()
myFoldM_ f a (x:xs) = (f a x) >>= (flip (myFoldM_ f) xs)

となります。

次回、最終回!