
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