How does the type of "ap = liftM2 id" work?

Hello, I'm a bit perplexed by what it means to do something like "ap = liftM2 id" liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r id :: a -> a liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r My intuitive understanding is that liftM2 is expecting a two-argument function as its first argument, so it seems a little unexpected to pass it "id", a one-argument function. And I can't really see how the type signature of "liftM2 id" is derived from "liftM2" and "id". Any help much appreciated! -- Matt

On Fri, Aug 22, 2008 at 2:07 PM, Quergle Quergle
Hello,
I'm a bit perplexed by what it means to do something like "ap = liftM2 id"
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r id :: a -> a liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r
My intuitive understanding is that liftM2 is expecting a two-argument function as its first argument, so it seems a little unexpected to pass it "id", a one-argument function. And I can't really see how the type signature of "liftM2 id" is derived from "liftM2" and "id". Any help much appreciated!
Just remember that 'a1 -> a2 -> r' is equivalent to '(a1) -> (a2 -> r)', and unifying this type with 'a -> a' gives a1 = a2 -> r So, liftM2's type becomes ((a2 -> r) -> a2 -> r) -> m (a2 -> r) -> m a2 -> m r Is it clearer now? HTH, -- Felipe.

On 2008 Aug 22, at 13:07, Quergle Quergle wrote:
id :: a -> a liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r
My intuitive understanding is that liftM2 is expecting a two-argument function as its first argument, so it seems a little unexpected to pass it "id", a one-argument function. And I can't really see how the
That's not quite how types work. "a -> a", with nothing constraining the "a", can be *any* type... including a function type. And because in Haskell a multiple-argument function is identical to a single- argument function returning a single-argument function, the type of "id" encompasses any number of arguments. So, "liftM2 id" constrains "id" by usage (as you noted, it requires a 2-argument function) to have the type "(a -> b) -> (a -> b)" instead of "a -> a", and now it works. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

Brandon S. Allbery KF8NH wrote:
Quergle Quergle wrote:
My intuitive understanding is that liftM2 is expecting a two-argument function as its first argument, so it seems a little unexpected to pass it "id", a one-argument function.
And because in Haskell a multiple-argument function is identical to a single-argument function returning a single-argument function, the type of "id" encompasses any number of arguments.
In other words, there are no two-argument functions in Haskell anyway. Every function has only one argument. Regards, apfelmus

Quergle Quergle wrote:
I'm a bit perplexed by what it means to do something like "ap = liftM2 id"
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r id :: a -> a liftM2 id :: (Monad m) => m (a2 -> r) -> m a2 -> m r
My intuitive understanding is that liftM2 is expecting a two-argument function as its first argument, so it seems a little unexpected to pass it "id", a one-argument function. And I can't really see how the type signature of "liftM2 id" is derived from "liftM2" and "id". Any help much appreciated!
Polymorphic values in Haskell have more then one type. Lets try to figure out a type of the id in liftM2 id. From the type signature of id, we know that it has to be a -> a for some a. From the type signature of liftM2, we know that is has to be a1 -> a2 -> r for some a1, a2 and r. Since a1 -> a2 -> r is a1 -> (a2 -> r), we have (a -> a) == a1 -> (a2 -> r) and therefore a == a1 == a2 -> r. If we substitute a2 -> r for both a and a1 in the types of id and liftM2, we see why liftM2 id is well-typed and one of its types: id :: (a2 -> r) -> (a2 -> r) liftM2 :: ((a2 -> r) -> (a2 -> r)) -> m (a2 -> r) -> m a2 -> m r liftM2 id :: m (a2 -> r) -> m a2 -> mr If you have problems with understand ap = liftM2 id, you may want to look into ($) = id first. Tillmann
participants (5)
-
apfelmus
-
Brandon S. Allbery KF8NH
-
Felipe Lessa
-
Quergle Quergle
-
Tillmann Rendel