# Cannot understand liftM2

19 messages
Open this post in threaded view
|

## Cannot understand liftM2

 Hi All, I'm loving learning Haskell quite a bit. It is stretching my brain but in a delightfull way. I've googled, I've hoogled but I haven't found a clear explanation for what exactly liftM2 does in the context below. Using the cool lambdabot "pointless" utility I found out that: > \x -> snd(x) - fst(x) is the same as: > liftM2 (-) snd fst I like the elegance of this but I cannot reconcile it with its type. I can't understand it. I check the signature of liftM2 and I get: Prelude> :t liftM2 Prelude> liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r Can someone help me understand what's happening here ? What does a Monad have to do with a simple subtraction ? What is actually the "m" of my example ? I am sure if I get this I'll be another step closer to illumination ... Thanks,    Nick _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci Quoth Nicola Paolucci, nevermore: > Prelude> :t liftM2 > Prelude> liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > > Can someone help me understand what's happening here ? > What does a Monad have to do with a simple subtraction ? > What is actually the "m" of my example ? I'm honestly not sure what the actual Monad m is in this case. I'm sure some enlightened individual will help us out. Maybe Identity? But I thought you might find this handy --- the interactive console will give you the type of whole expressions, not just bare functions. It can be pretty helpful when trying to decode typery. > :t liftM2 > liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > :t liftM2 (-) > liftM2 (-) :: (Num a1, Monad m) => m a1 -> m a1 -> m a1 > :t liftM2 (-) snd > liftM2 (-) snd :: (Num b) => ((a, b) -> b) -> (a, b) -> b > :t liftM2 (-) snd fst > liftM2 (-) snd fst :: (Num a) => (a, a) -> a Cheers, D. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci "Nicola Paolucci" <[hidden email]> writes: > Hi All, > > I'm loving learning Haskell quite a bit. > It is stretching my brain but in a delightfull way. > > I've googled, I've hoogled but I haven't found a clear explanation for > what exactly liftM2 does in the context below. > > Using the cool lambdabot "pointless" utility I found out that: > > > \x -> snd(x) - fst(x) > > is the same as: > > > liftM2 (-) snd fst > > I like the elegance of this but I cannot reconcile it with its type. I > can't understand it. > I check the signature of liftM2 and I get: > > Prelude> :t liftM2 > Prelude> liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > > Can someone help me understand what's happening here ? > What does a Monad have to do with a simple subtraction ? > What is actually the "m" of my example ? > > I am sure if I get this I'll be another step closer to illumination ... Does typing  :t liftM2 (-) snd into ghc enlighten you at all? -- Jón Fairbairn                                 [hidden email] _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Re: Cannot understand liftM2

 On 11 Dec 2006 16:55:17 +0000, Jón Fairbairn <[hidden email]> wrote: > "Nicola Paolucci" <[hidden email]> writes: > > > Hi All, > > > > I'm loving learning Haskell quite a bit. > > It is stretching my brain but in a delightfull way. > > > > I've googled, I've hoogled but I haven't found a clear explanation for > > what exactly liftM2 does in the context below. > > > > Using the cool lambdabot "pointless" utility I found out that: > > > > > \x -> snd(x) - fst(x) > > > > is the same as: > > > > > liftM2 (-) snd fst > > > > I like the elegance of this but I cannot reconcile it with its type. I > > can't understand it. > > I check the signature of liftM2 and I get: > > > > Prelude> :t liftM2 > > Prelude> liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > > > > Can someone help me understand what's happening here ? > > What does a Monad have to do with a simple subtraction ? > > What is actually the "m" of my example ? > > > > I am sure if I get this I'll be another step closer to illumination ... > > Does typing > >  :t liftM2 (-) snd > > into ghc enlighten you at all? > Make sure to   :m + Control.Monad.Reader first, because this instance unfortunately isn't in the Prelude. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci > I'm loving learning Haskell quite a bit. > It is stretching my brain but in a delightfull way. Great! > Using the cool lambdabot "pointless" utility I found out that: > >> \x -> snd(x) - fst(x) > > is the same as: > >> liftM2 (-) snd fst Yes, the '(->) c' monad is very handy. One way to think about it is viewing 'f :: c -> a' as a set of 'a''s, indexed by the set of 'c''s. The monad operations are then easily understood as doing things 'pointwise': given some specific index (e.g. 'x'), you use this index to select the appropriate value of every relevant indexed object (e.g. 'snd' and 'fst'), and then apply the unlifted function (e.g. '(-)') to those. Another way to write the above function is 'uncurry (flip (-))', or 'uncurry subtract'. Regards, Arie _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Cale Gibbard Hi All, Hi Cale, Can you tell me if I understood things right ? Please see below ... On 12/11/06, Cale Gibbard <[hidden email]> wrote: > The monad instance which is being used here is the instance for ((->) > e) -- that is, functions from a fixed type e form a monad. > > So in this case: > liftM2 :: (a1 -> a2 -> r) -> (e -> a1) -> (e -> a2) -> (e -> r) > I bet you can guess what this does just by contemplating the type. (If > it's not automatic, then it's good exercise) Now, why does it do that? So the way I have to reason on the output I get from ghci is: Prelude> :t liftM2 liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r The m stands for ((->) e), that is like writing (e -> a1): a function which will take an argument of type e and will return an argument of type a1. And so the above line has a signature that reads something like: liftM2 will takes 3 arguments: - a function (-) that takes two arguments and returns one result of type r. - a function (fst) that takes one argument and returns one result. - a function (snd) that takes one argument and returns one result. - the result will be a certain function that will return the same type r of the (-) function. - Overall to this liftM2 I will actually pass two values of type a1 and a2 and will get a result of type r. >From the type signature - correct me if I am wrong - I cannot actually tell that liftM2 will apply (-) to the rest of the expression, I can only make a guess. I mean I know it now that you showed me: > liftM2 f x y = do >    u <- x >    v <- y >    return (f u v) If this is correct and it all makes sense, my next question is: - How do I know - or how does the interpreter know - that the "m" of this example is an instance of type ((->) e) ? - Is it always like that for liftM2 ? Or is it like that only because I used the function (-) ? I am trying to understand this bit by bit I am sorry if this is either very basic and easy stuff, or if all I wrote is completely wrong and I did not understand anything. :D Feedback welcome. Thanks again, Regards,     Nick _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci Hi, > So the way I have to reason on the output I get from ghci is: > > Prelude> :t liftM2 > liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > > The m stands for ((->) e), that is like writing (e -> a1): a function > which will take an argument of type e and will return an argument of > type a1. > > And so the above line has a signature that reads something like: > liftM2 will takes 3 arguments: > - a function (-) that takes two arguments and returns one result of   > type r. > - a function (fst) that takes one argument and returns one result. > - a function (snd) that takes one argument and returns one result. > - the result will be a certain function that will return the same type > r of the (-) function. > - Overall to this liftM2 I will actually pass two values of type a1 > and a2 and will get a result of type r. > >> From the type signature - correct me if I am wrong - I cannot   >> actually > tell that liftM2 will apply (-) to the rest of the expression, I can > only make a guess. I mean I know it now that you showed me: > >> liftM2 f x y = do >>    u <- x >>    v <- y >>    return (f u v) > > If this is correct and it all makes sense, my next question is: > - How do I know - or how does the interpreter know - that the "m" of > this example is an instance of type ((->) e) ? > - Is it always like that for liftM2 ? Or is it like that only because > I used the function (-) ? > > I am trying to understand this bit by bit I am sorry if this is either > very basic and easy stuff, or if all I wrote is completely wrong and I > did not understand anything. :D Feedback welcome. You can derive this yourself by assigning types to all parts of the   expression and working things out, i.e., doing the type inference   yourself. For example, liftM2 :: T1 =  T2 -> T3 -> T4 -> T5 because liftM2 consumes three   arguments. Furthermore, ghci gives you the type of liftM2, you know   the type of (-) and the types of snd and fst. Therefore, T2 = (a -> a -> a) (type of (-)) T3 = (b,c) -> c (type of snd) T4 = (d,e) -> d (type of fst) and, by the type of liftM2 :: (f -> g -> h) -> m f -> m g -> m h, we   also have T2 = (f -> g -> h) T3 = m f T4 = m g T5 = m h The two type expressions for T2 imply that f = g = h = a (type-wise,   that is). And m f = (b,c) -> c = ((->) (b,c)) c m g = (d,e) -> d = ((-> (d,e)) d, because f = g this reduces to ((->)   (c,c)) c and thus : m h = (c,c) -> c, because f = g = h This implies that the monad m = ((->) (c,c)) and h = c = a = f = g Thus: liftM2 (-) snd fst :: ((->) (a,a)) a = (a,a) -> a If I made any errors, please tell me. -- Andy _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci On 12/11/06, Nicola Paolucci <[hidden email]> wrote: > I am trying to understand this bit by bit I am sorry if this is either > very basic and easy stuff, or if all I wrote is completely wrong and I > did not understand anything. :D Feedback welcome. Don't apologise - I, for one, am finding this discussion very informative, and am reading the responses with interest. Thanks for starting the thread! Paul. _______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Re: Cannot understand liftM2

Open this post in threaded view
|

## Re: Cannot understand liftM2

 In reply to this post by Nicola Paolucci > Using the cool lambdabot "pointless" utility I found out that: > >> \x -> snd(x) - fst(x) > > is the same as: > >> liftM2 (-) snd fst > > I like the elegance of this but I cannot reconcile it with its type. I > can't understand it. > I check the signature of liftM2 and I get: > > Prelude> :t liftM2 > Prelude> liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r > > Can someone help me understand what's happening here ? > What does a Monad have to do with a simple subtraction ? > What is actually the "m" of my example ? I think the simplest way to understand liftM and liftM2 are in terms of their do-notation:      liftM op act = do          x <- act          return (op x) that is: perform the action, bind the result to x, compute (op x) and return that in the monad. Similarly for liftM2:     liftM2 op act1 act2 = do         x <- act1         y <- act2         return (x `op` y) in your case:     liftM2 (-) snd fst = do         x <- snd         y <- fst         return (x - y) this is in the monad of functions that require an argument.  Snd is a function that takes an argument (a pair) and returns a value (the 2nd member of the pair).  Similarly fst is a fnction that takes an argument.  The whole do-block represents a function that takes an argument (also a pair).  As usual, do-blocks combine several actions (in this case functions of one arguments) into a new action. The description for this one is:  the function that, when given an argument (say "a") computes the snd item of the pair (snd a) binds, computes the fst item of the pair (fst a) and subtracts the two values (snd a - fst a). >  Nick Tim Newsham http://www.thenewsh.com/~newsham/_______________________________________________ Haskell-Cafe mailing list [hidden email] http://www.haskell.org/mailman/listinfo/haskell-cafe
Open this post in threaded view
|

## Re: Cannot understand liftM2

 Nice explanation.  However, at http://stackoverflow.com/questions/4119730/cartesian-product it was pointed out that this cartProd :: [a] -> [b] -> [(a, b)] cartProd = liftM2 (,) is equivalent to the cartesian product produced using a list comprehension: cartProd xs ys = [(x,y) | x <- xs, y <- ys] I do not see how your method of explanation can be used to explain this equivalence?  Nevertheless, can you help me to understand how liftM2 (,) achieves the cartesian product?  For example, Prelude Control.Monad.Reader> liftM2 (,) [1,2] [3,4,5] [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)] Thank you!
Open this post in threaded view
|