[Haskell-beginners] Ignoring the result of a monadic computation

Aleksandar Dimitrov aleks.dimitrov at googlemail.com
Fri Nov 19 08:02:22 EST 2010


Hello Tim,

> while learning about monads, I had something like
> 
> do
>    line <- getLine
>    something
>    putStrLn line

This is written in do-notation. Let's look at it without do-notation:

> getLine >>= (\line -> something >>= (\_ -> putStrLn line))

Or, using `const` which is probably a bit clearer:

> getLine >>= (\line -> something >>= const $ putStrLn line)

The do-nation implicitly discards the result of 'something,' even though
something may have a result!
In fact, a couple of versions ago, ghc started warning you if 'something' had a
type other than M () and you weren't binding it:

> % cat Test.hs
> main :: IO ()
> main = do print "Hello"
>           getChar
>           print "Goodbye"
> % ghc -Wall --make Test.hs
> [1 of 1] Compiling Main             ( Test.hs, Test.o )
> 
> Test.hs:3:10:
>     Warning: A do-notation statement discarded a result of type Char.
>              Suppress this warning by saying "_ <- getChar",
>              or by using the flag -fno-warn-unused-do-bind

So you'd have to rewrite your code like this to compile without warnings:

> do line <- getLine
>    _ <- something
>    putStrLn line

That way, it is clear that even though you're using the do-notation, you're
discarding the result of a computation, and are executing the computation just
for its side-effects!

> and I wondered if I could write it in one line, without naming of parameters.

As you can see above, one can write it in one line. It is also possible to use
(>>); (>>) is similar to (>>=) except it doesn't *bind* the result. It also has
a different type:

> (>>=) :: m a -> (a -> m b) -> m b
> (>>)  :: m a -> m b -> m b

(>>=) expects a function from a to m b as a second argument, but since (>>)
doesn't bind a result at all, such a function wouldn't make any sense! So (>>)
just takes another computation, and chains these. You could rewrite the one-line
statement above as

> getLine >>= (\line -> something >> putStrLn line)

which does read a little better. But the do-notation really does make our lives
easier! It makes the λ-binding of variables more implicit. So we can use it in
the following way:

> do line <- getLine
>    something >> putStrLn line

This way, it is clear that something's result is going to be thrown away (if
there is any,) and something is just executed for its side-effects.

> % cat Test.hs                                                                       ~
> something = getChar
> 
> main :: IO ()
> main = do line <- getLine
>           something >> putStrLn line
> % ghc -Wall --make Test.hs
> % ./Test                                                                            ~
> foobar
> .
> foobar

As you can see, I typed in 'foobar' which got bound to 'line.' But then I got
prompted to also put in a character, which got discarded.

I hope this makes it a little clearer!

A.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: Digital signature
Url : http://www.haskell.org/pipermail/beginners/attachments/20101119/b5d05217/attachment.bin


More information about the Beginners mailing list