Reputation: 1241
I am learning about the Writer Monad on the book Learn You A Haskell.
this is the piece of code:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber num = writer (num, ["Got number: " ++ show num])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a * b)
When running multWithLog
, this is the result:
*Main> runWriter multWithLog
(15,["Got number: 3","Got number: 5"])
On this lines:
a <- logNumber 3
b <- logNumber 5
It is easy to see that a = 3
and b = 5
, since both of them are being multiplied on the return
function.
What I don't understand is why those values are 3
and 5
. Shouldn't a
and b
be the values that contain inside the Writer
Monad? In this case tuples?
For example, with this was with the Maybe
Monad, a
and b
would be 3
and 5
:
do
a <- Just 3
b <- Just 5
return (a * b)
In this case it makes sense to me, since a
and b
receive the content inside Just
. But with the initial example, a
and b
only receive part of the value.
Upvotes: 3
Views: 2587
Reputation: 30237
It is easy to see that a = 3 and b = 5, since both of them are being multiplied on the return function. What I don't understand is why those values are 3 and 5. Shouldn't a and b be the values that contain inside the Writer Monad? In this case tuples?
No. I think the simplest way to answer this is to just implement the Writer
type and study its Monad
class instance:
newtype Writer w a = Writer { runWriter :: (a, w) }
instance Functor (Writer w) where
fmap f (Writer (a, w)) = Writer (f a, w)
instance Monoid w => Applicative (Writer w) where
pure a = Writer (a, mempty)
Writer (f, w) <*> Writer (a, w') = Writer (f a, w <> w')
instance Monoid w => Monad (Writer w) where
return = pure
Writer (a, w) >>= f = let (b, w') = runWriter (f a)
in Writer (b, w <> w')
tell :: w -> Writer w ()
tell w = Writer ((), w)
As you can see in the instance method for >>=
, the function f
is applied to the a
value, not the whole tuple. The syntax a <- logNumber 3
is desugared using >>=
, so the value that's bound to a
will be the first element of the tuple that Writer
wraps around.
Upvotes: 6
Reputation: 34398
In this case it makes sense to me, since
a
andb
receive the content insideJust
. But with the initial example,a
andb
only receive part of the value.
There is nothing really wrong with this description, but we can also look at this situation in another way. In...
a <- Just 3
... we might also say that a
receives only part of Just 3
-- the Just
wrapper does not make it. From that point of view, what happens with...
a <- writer (3, ["Got number: " ++ show 3])
... is quite similar: a
only receives the 3
value. The [String]
annotations, so to say, stay in the background, getting mappend
ed into each other by the monadic binds, much like (>>=)
combines Maybe
s so that Just
with Just
gives Just
and Nothing
with anything gives Nothing
.
Upvotes: 3
Reputation: 120751
The idea of “values contained in a monad” is a bit fuzzy. It kind of works, but not rigorously.
Really, a monad as such doesn't “contain” anything. It's not actually a spacesuit or burrito, you know...
In the case of Writer
, you can say clearly that this is a type whose values contain both log-snippets and computation-results. The latter is what you might interpret as the “content” of the monad, and is what you can retrieve with a <-
. But in general, there needn't be any such content at all.
In fact, to stay with your Maybe
example:
do a <- Just 3
Nothing
b <- Just 5
return (a * b)
In this case, the Nothing
“interrupts” the computation, so the Just 5
doesn't ever get to inject the value 5
into a
.
The thing to keep in mind is that, if action :: M T
for some monad M
, then
do
...
a <- action
can give a
a value of type T
. (In your example, M
is Writer [String]
and T
is Int
, so a
can only have type Int
.)
Whether that actually happens, how often, where the values come from and what it means depends on the particular monad. Still, the monad laws can tell you a lot about the whole computation will behave. But while learning about monads, it's probably best to forget about all this, simply look at many different examples and dabble with monads yourself, at some point you'll get an intuition for them. Don't try too hard to “understand” monads through analogies.
Upvotes: 2