
Hi Paul Its Pointfree that's choosing `ap` - I've never got round to using it myself but I assume it only re-writes using only "standard" functions (Prelude + Base?). As there isn't a specific definition of Starling available for the functional type it chooses Monadic ap. Nowadays it could also choose (<*>) from Control.Applicative. The monad instance for functions is the Reader monad without a newtype wrapper: m x == (r1 -> x) ap :: (Monad m) => m (a -> b) -> m a -> m b Subsituting you get: ap :: (r1 -> a -> b) -> (r1 -> a) -> (r1 -> b) If you want you can knocking out the bracket of the last part... ap :: (r1 -> a -> b) -> (r1 -> a) -> r1 -> b Same with liftM2 liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r Nicer var names: liftM2 :: (Monad m) => (a -> b -> ans) -> m a -> m b -> m ans Substituting, m x == (r1 -> x) liftM2 :: (a -> b -> c) -> (r1 -> a) -> (r1 -> b) -> (r1 -> ans) This matches the Phoenix combinator also known as Big Phi. I think it was in the combinator set used by David Turner in the implementation of SASL (SASL's abstract machine used combinators as its machine code). phoenix :: (a -> b -> ans) -> (r1 -> a) -> (r1 -> b) -> r1 -> ans