
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.