Looking at some Writer
monad examples, in the one from Learn You a Haskell I don't see where the use of *
multiplication operator in the last line expression is overloaded to work with the with the Writer
objects produced by the logNumber
functions:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
CodePudding user response:
There seems to be some misunderstanding here. In your example code:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
the values a
and b
are not Writer
values. Their type is simply Int
, and of course you can multiply 2 Int
s. Therefore a*b
is an Int
too - note the use of return
on it in the last line, which is needed here precisely in order to "lift" the "ordinary value" a*b
of type Int
to a "monadic value" of type Writer [String] Int
.
logNumber 3
is certainly a monadic value (of type Writer [String] Int
), but the <-
syntactic sugar of do
notation "extracts" the underlying value out of it, and gives it a name - here a
. More precisely, the do
block above desugars to:
multWithLog = logNumber 3 >>= \a -> logNumber 5 >>= \b -> return (a*b)
where the lambda expressions have type Int -> Writer [String] Int
(the arguments a
and b
being the Int
s in question), which due to the type of >>=
produces an expression of type Writer [String] Int
overall.