
On Fri, Mar 08, 2013 at 08:53:15PM -0800, Edward Z. Yang wrote:
Are these equivalent? If not, under what circumstances are they not equivalent? When should you use each?
evaluate a >> return b a `seq` return b return (a `seq` b)
Furthermore, consider: [...] - Does the underlying monad (e.g. if it is IO) make a difference? [...]
Here's a monad transformer DelayT which adds an "evaluate" operation to any monad. Perhaps it will help in understanding the situation. (NB it only has the desired behaviour for monads which must force x to at least WHNF before they can perform the action associated with x >>= f, so Identity won't do, for example). % cat evaluate.hs && ghc -fforce-recomp evaluate.hs && ./evaluate import Control.Monad.Trans.Class (lift, MonadTrans) data DelayT m a = DelayT (m a) deriving Show unlift :: DelayT m a -> m a unlift (DelayT x) = x instance Monad m => Monad (DelayT m) where return = lift . return x >>= f = lift $ unlift x >>= unlift . f instance MonadTrans DelayT where lift = DelayT evaluate :: Monad m => a -> DelayT m a evaluate = lift . (return $!) type M = Maybe should_succeed :: Bool should_succeed = x `seq` () == () where x :: DelayT M () x = evaluate undefined should_fail :: DelayT M () should_fail = evaluate undefined >> return () main = do putStrLn "Should succeed" print should_succeed putStrLn "Should fail" print should_fail [1 of 1] Compiling Main ( evaluate.hs, evaluate.o ) Linking evaluate ... Should succeed True Should fail evaluate: Prelude.undefined