[Haskell-beginners] Question about example in 'using do notation with Writer' section of LYH
Theodore Lief Gannon
tanuki at gmail.com
Fri Jan 27 08:34:29 UTC 2017
Fully expanding your program might help. One of the great things about
Haskell is equational reasoning: if two things have been declared equal,
you can substitute one for the other.
First, let's desugar that do notation to the equivalent bind chain:
multWithLog =
logNumber 3 >>= \a ->
logNumber 5 >>= \b ->
return (a*b)
Evaluate the logNumber and return calls to normal form from their
definitions, also considering the monoid definitions of (++) and mempty for
lists:
multWithLog =
Writer (3, ["Got number: 3"]) >>= \a ->
Writer (5, ["Got number: 5"]) >>= \b ->
Writer (a*b, [])
Now, refer to the definition of (>>=) for Writer (as shown in LYAH):
(Writer (x, v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v
`mappend` v')
Rewritten as a lamba (and replacing `mappend` with (++) for brevity), this
becomes:
\(Writer (x, v)) f -> let (Writer (y, v')) = f x in Writer (y, v++v')
It's no longer an infix function, so we'll have to shift things around a
little. Here's what it expands to:
multWithLog =
(\(Writer (x, v)) f -> -- \
let (Writer (y, v')) = f x -- | bind
in Writer (y, v++v')) -- /
(Writer (3, ["Got number: 3"])) -- Writer (x, v)
(\a -> -- f
(\(Writer (x2, v2)) f2 -> -- \
let (Writer (y2, v2')) = f2 x2 -- | bind
in Writer (y2, v2++v2')) -- /
(Writer (5, ["Got number: 5"])) -- Writer (x2, v2)
(\b -> Writer (a*b, [])) -- f2
) -- (end f)
Now it's just a matter of simplification. Let's start by eliminating the
first argument of each bind, i.e. (Writer (x,v)), by substituting with
concrete values.
multWithLog =
(\f -> -- \ partially
let (Writer (y, v')) = f 3 -- | applied
in Writer (y, ["Got number: 3"]++v')) -- / bind
(\a -> -- f
(\f2 -> -- \ partially
let (Writer (y2, v2')) = f2 5 -- | applied
in Writer (y2, ["Got number: 5"]++v2')) -- / bind
(\b -> Writer (a*b, [])) -- f2
) -- (end f)
Substitute f2, and eliminate both \f2 and \b in the same way:
multWithLog =
(\f ->
let (Writer (y, v')) = f 3
in Writer (y, ["Got number: 3"]++v'))
(\a ->
let (Writer (y2, v2')) = Writer (a*5, []) -- applied f2
in Writer (y2, ["Got number: 5"]++v2')
)
With a full match on the inner let block, that can also be eliminated:
multWithLog =
(\f ->
let (Writer (y, v')) = f 3
in Writer (y, ["Got number: 3"]++v'))
(\a -> Writer (a*5, ["Got number: 5"]++[]))
I'll forego the last few substitutions. If it's still not clear how you get
to the final output, you should run through them yourself. You'll
eventually reach a static definition of the result -- which shouldn't
really be surprising, since there were no arguments to this "function" and
its type doesn't contain -> anywhere. :)
On Thu, Jan 26, 2017 at 1:34 PM, Olumide <50295 at web.de> wrote:
> On 26/01/17 16:02, David McBride wrote:
>
>> runWriter multWithLogTuple
>>>
>> ((3,5,10),["Got number: 3","Got number: 5"])
>>
>
> On second thoughts I don't think I understand how the logs are
> concatenated. I was expecting (15,["Got number: 15") in the original
> example.
>
>
> - Olumide
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20170127/e89ffc45/attachment.html>
More information about the Beginners
mailing list