[Haskell-cafe] The essence of my monad confusion

Brent Yorgey byorgey at seas.upenn.edu
Sat May 2 12:58:37 EDT 2009


On Sat, May 02, 2009 at 05:31:03PM +0100, Paul Keir wrote:
> On the wiki page for Applicative Functors (http://www.haskell.org/haskellwiki/Applicative_functor) a familiar characteristic of monads is quoted; that they "allow you to run actions depending on the outcomes of earlier actions". I feel comfortable with Functors and Applicative Functors, but I don't yet get that "extra power" that monads provide.
> 
> An example immediately follows that quotation on the wiki:
> 
> do text <- getLine
>    if null text
>      then putStrLn "You refuse to enter something?"
>      else putStrLn ("You entered " ++ text)
> 
> For simplicity's sake, I modified it to avoid using the IO monad; the "text" binding is now provided by the first parameter, and (=<<) is used due to its similarity to fmap:
> 
> bar :: Monad m => m String -> m String
> bar as = (=<<)  (\a -> if null a then return "nothing" else return "something")  as

This simplification does not preserve the crucial aspect of the
example: (putStrLn "blah") has an effect (namely, printing something
on the screen), whereas (return "blah") never has an effect (whatever
"effect" means for the particular monad in question).  You seem to be
confusing the return value of a monadic computation with its side
effects.  In the case of 'putStrLn "blah"', the return value is (),
and the side effect is to print "blah" to the screen; in the case of
'return "blah"', the return value is "blah" and there are no side
effects.

Since IO is a monad, we can compute the result of 'getLine' and then
use it to decide which of the two putStrLns to run; the effect of the
other one (printing something on the screen) will never happen.  But
there is no way to do this with only the Applicative interface.  Try
writing a function

  f :: IO String -> IO () -> IO () -> IO ()

which has the same behavior as the 'do text <- getLine...' example
above, using *only* the Applicative instance of IO; you won't be able
to do it.  Depending how you implement f, it may execute only the
first IO (), or only the second, or both, or neither; but it will
always be the same.  You won't be able to have f choose which to
execute based on the result of the IO String parameter.

-Brent


More information about the Haskell-Cafe mailing list