Question about example in 'using do notation with Writer' section of LYH

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Question about example in 'using do notation with Writer' section of LYH

Olumide
Hello List,

Chapter 14 of LYH (
http://learnyouahaskell.com/for-a-few-monads-more#reader ) has the
following bit of 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)

I have a fair grasp of what's going bu the last line return(a*b) eludes
me. Specifically its the a*b part that baffles me. I think 3 is bound to
'a' and 5 to 'b', then return(a*b) would put the value 15 in a context
... So what becomes of the string parts of the Writer monads created by
logNumber 3 and logNumber 5 respectively.

Regards,

- Olumide
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

David McBride
Nothing happens to them.  They are still in there.  Whereas logNumber
always returns the number you give it, multiWithLog always returns 15
and appends two strings into its state ("got number 3 and 5").

You can return whatever value you want from a Monad.  In this case
he's doing a * b, but you could do 2 * b, Just (a + b) or anything
else.  As an example, here I return a tuple instead.

multWithLogTuple :: Writer [String] (Int,Int,Int)
multWithLogTuple = do
    a <- logNumber 3
    b <- logNumber 5
    return (a,b,2*b)


>runWriter multWithLogTuple
((3,5,10),["Got number: 3","Got number: 5"])

On Thu, Jan 26, 2017 at 10:41 AM, Olumide <[hidden email]> wrote:

> Hello List,
>
> Chapter 14 of LYH ( http://learnyouahaskell.com/for-a-few-monads-more#reader
> ) has the following bit of 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)
>
> I have a fair grasp of what's going bu the last line return(a*b) eludes me.
> Specifically its the a*b part that baffles me. I think 3 is bound to 'a' and
> 5 to 'b', then return(a*b) would put the value 15 in a context ... So what
> becomes of the string parts of the Writer monads created by logNumber 3 and
> logNumber 5 respectively.
>
> Regards,
>
> - Olumide
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

Imants Cekusins
In reply to this post by Olumide
what becomes of the string parts of the Writer monads

multWithLog keeps [String] and outputs Int

to fully benefit from Writer [String] Int, you'd call e.g. runWriter or execWriter

similar to other State state out monads, 

m state out lets you get/set/keep state as needed without passing it as an arg. state is there if you need it.




_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

Olumide
In reply to this post by David McBride
On 26/01/2017 16:02, David McBride wrote:

> Nothing happens to them.  They are still in there.  Whereas logNumber
> always returns the number you give it, multiWithLog always returns 15
> and appends two strings into its state ("got number 3 and 5").
>
> You can return whatever value you want from a Monad.  In this case
> he's doing a * b, but you could do 2 * b, Just (a + b) or anything
> else.  As an example, here I return a tuple instead.
>
> multWithLogTuple :: Writer [String] (Int,Int,Int)
> multWithLogTuple = do
>     a <- logNumber 3
>     b <- logNumber 5
>     return (a,b,2*b)
>

So return (a*b) still creates Writer [String] Int?

I thought the [String] parts of 'a' and 'b' ought to be in the result
but I see it needn't.

- Olumide


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

Olumide
In reply to this post by David McBride
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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

Theodore Lief Gannon
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 <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about example in 'using do notation with Writer' section of LYH

Olumide
On 27/01/2017 08:34, Theodore Lief Gannon wrote:

> 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')
>

Thank you for your explanation. The substitutions helped a lot even
though I wasn't able to follow the equational reasoning. The expansion
gave me enough starting information to figure out what's going on by
starting from the innermost bind.

BTW, I thought the definition of (>>=) was supposed to come from
Control.Monad.Writer.

Regards,

- Olumide


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Loading...