do 記法から(>>=)を使った記法へ変換

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まで定義されています。