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 |
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 |
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 |
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 |
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 |
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 = Evaluate the logNumber and return calls to normal form from their definitions, also considering the monoid definitions of (++) and mempty for lists:
Now, refer to the definition of (>>=) for Writer (as shown in LYAH):
Rewritten as a lamba (and replacing `mappend` with (++) for brevity), this becomes:
It's no longer an infix function, so we'll have to shift things around a little. Here's what it expands to:
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.
Substitute f2, and eliminate both \f2 and \b in the same way:
With a full match on the inner let block, that can also be eliminated:
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: _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
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 |
Free forum by Nabble | Edit this page |