I have a question regarding a block of code from th Week04 Plutus Pioneer Program. The block is in Writer.hs
foo'' :: Writer Int -> Writer Int -> Writer Int -> Writer Int
foo'' x y z = do
s <- threeInts x y z
tell ["sum: " ++ show s]
return s
For reference,
threeInts :: Monad m => m Int -> m Int -> m Int -> m Int
threeInts mx my mz =
mx >>= \k ->
my >>= \l ->
mz >>= \m ->
let s = k + l + m in return s
tell :: [String] -> Writer ()
tell = Writer ()
instance Monad Writer where
return a = Writer a []
number :: Int -> Writer Int
number n = Writer n $ ["number: " ++ show n]
Why does
foo'' (number 2) (number 3) (number 4)
return
Writer 9 ["number: 2","number: 3","number: 4","sum: 9"]
and not
Writer 9 []
Obviously there are holes in my understanding, but I read the do
block as follows:
- The result of
threeInts x y z
isWriter 9 ["number: 2","number: 3","number: 4"]
- 9 is extracted from this to the definition
s
tell ["sum: " ++ show s]
results inWriter () ["sum: 9"]
return s
results inWriter 9 []
I know that return
in Haskell is not the same as it is in an imperative language, but I'm failing miserably to grok how to read this block effectively. The lambda version producing the same result is more explicit and makes sense to me.
bindWriter :: Writer a -> (a -> Writer b) -> Writer b
bindWriter (Writer a xs) f =
let
Writer b ys = f a
in
Writer b $ xs ++ ys
foo' :: Writer Int -> Writer Int -> Writer Int -> Writer Int
foo' x y z = x `bindWriter` \k ->
y `bindWriter` \l ->
z `bindWriter` \m ->
let s = k + l + m
in tell ["sum: " ++ show s] `bindWriter` \_ ->
Writer s []
I read this backwards where (for my concrete example) Writer 9 []
is bound/combined with Writer () ["sum: 9"]
which is then bound/combined with Writer 4 ["number: 4"]
, Writer 3 ["number: 3"]
and Writer 2 ["number: 2"]
where the Int values are discarded in the bind process and the "logs" are concatenated.
There is something implicit in the do
notation that I'm overlooking or not reading correctly. Any help appreciated.