Haskell 遅延評価と即時評価

必要になるまで評価されない、という遅延評価の理解だけでは、
一見、以下の実行例は不可解。

Prelude> :m Control.Monad
Prelude Control.Monad> liftM3 maybe (fail "$$$$") (return id) (return (Just 3.14))
*** Exception: user error ($$$$)

Prelude> :m Control.Applicative
Prelude Control.Applicative> maybe <$> (fail "$$$$") <*> (return id) <*> (return (Just 3.14))
*** Exception: user error ($$$$)

liftM3 の実装を見て謎が解けた。

liftM3  :: (Monad m) => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 f m1 m2 m3       = do { x1 <- m1; x2 <- m2; x3 <- m3; return (f x1 x2 x3) }

なるほどね。