[Haskell-beginners] Need help understanding the tell function in the Monad Writer example in LYAH
Francesco Ariis
fa-ml at ariis.it
Fri Feb 3 13:54:20 UTC 2017
On Fri, Feb 03, 2017 at 11:31:32AM +0000, Olumide wrote:
> Hello List,
>
> Would someone kindly explain how the tell function interacts with the Writer
> Monad as show below:
> (Example taken from chapter 14 of LYAH
> http://learnyouahaskell.com/for-a-few-monads-more#reader )
>
> multWithLog :: Writer [String] Int
> multWithLog = do
> a <- logNumber 3
> b <- logNumber 5
> tell ["Gonna multiply these two"]
> return (a*b)
>
> Result:
> ghci> runWriter multWithLog
> (15,["Got number: 3","Got number: 5","Gonna multiply these two"])
>
> I know that tell function binds to an argument that is discarded but I don't
> know how its argument "Gonna multiply these two" is concatenated with the
> other the Writer created by logNumber 3 and logNumber 5.
>
> Also, I don't understand the paragraph following the example:
>
> "It's important that return (a*b) is the last line, because the result of
> the last line in a do expression is the result of the whole do expression.
> Had we put tell as the last line, () would have been the result of this do
> expression. We'd lose the result of the multiplication. However, the log
> would be the same."
>
>
> Regards,
>
> - Olumide
Hello Olumide,
a Writer do block can be read as a series of function which all have
a "hidden parameter". This parameter is the pile of log messages.
So you could as well substitute `tell ...` with
myTell :: String -> Writer [String] ()
myTell s = writer ((), [s])
and then in the do block
-- ... receiving a list of log messages
c <- myTell "something" -- adding mine to the list (and binding
-- a variable)
return (a*b) -- c is not being used!
-- but the log message *is* there
You can verify this yourself by adding `logNumber` statement in a do
block and not using them in the last return statement. There too log
will appear even if the bound variable is unused.
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5 -- not used but logged
-- equivalent to: logNumber 5 (without b <-)
return (a)
> Also, I don't understand the paragraph following the example:
>
> "It's important that return (a*b) is the last line, because the result of
> the last line in a do expression is the result of the whole do expression.
> Had we put tell as the last line, () would have been the result of this do
> expression. We'd lose the result of the multiplication. However, the log
> would be the same."
`tell` is really not much different from `myTell`. Let's examine it again:
myTell :: String -> Writer [String] ()
myTell s = writer ((), [s])
See the ()? It means it is *actually* returning something, a ().
Remember that `return` isn't the same `return` as in some imperative
languages: it only wraps a value in the monad we are using:
return 5
-- takes `5` and 'lifts' so it is usable inside the Writer
-- monad: `(5, [])`
Putting a `tell "something"` after a return statement would overwrite
that result (and gives us back a () instead).
Did this help?
My tip for really getting a Monad in your brain is to reimplement it.
It is a very useful exercise.
Also learning *not* to use the `do notation` helps too, as having
operators instead of magic makes things easier to understand.
More information about the Beginners
mailing list