do記法は構文糖です。
Real World Haskell
p356 14章モナド:「モナド初心者だと感じているうちは構文糖であるdo記法を使うより(>>=)を明示的に書いた方が良いでしょう」とありますので、とりあえず、極力do記法は避けるよう努力してみます。
ioHello, ioWorld :: IO String ioHello = return "Hello" ioWorld = return "world!" hello :: IO () hello = do a <- ioHello b <- ioWorld putStrLn $ a ++ "," ++ b hello2 :: IO () hello2 = showHello =<< ioHello where showHello a = (\b -> putStrLn $ a ++ "," ++ b) =<< ioWorld
ghci> hello --=> Hello,world! ghci> hello2 --=> Hello,world!
モナドに関数を摘要するための LiftM を (>>=) で書き直してみます。
-- | Promote a function to a monad. -- liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r -- liftM f m1 = do { x1 <- m1; return (f x1) } myLiftM :: (Monad m) => (a -> b) -> m a -> m b myLiftM f m1 = m1 >>= (\x1 -> return (f x1))
> let str = return "Hello"::Maybe String > myLiftM (++".world!") str -- => Just "Hello.world!" > myLiftM (++".world!") Nothing -- => Nothing > myLiftM length $ myLiftM (++".world!") str -- => Just 12 > myLiftM length $ myLiftM (++".world!") Nothing -- => Nothing
摘要する関数の引数が二つある場合。
-- liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r -- liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) } myLiftM2 :: (Monad m) => (a2 -> a1 -> a) -> m a2 -> m a1 -> m a myLiftM2 f m1 m2 = m1 >>= func where func x1 = m2 >>= func2 where func2 x2 = return (f x1 x2)
> myLiftM2 (+) [0,1] [0,2] -- => [0,2,1,3] > myLiftM2 (+) (Just 1) Nothing -- => Nothing > myLiftM2 (+) (Just 3) (Just 5) -- => Just 8
Control.Monadには引数が5個のliftM5まで定義されています。