Andy Georges andy.georges at elis.ugent.be
Mon Dec 11 15:33:21 EST 2006

```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

-- Andy

```