For the function monad I find that (<*>)
and (>>=)
/(=<<)
have two strikingly similar types. In particular, (=<<)
makes the similarity more apparent:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
(=<<) :: (a -> r -> b) -> (r -> a) -> (r -> b)
So it's like both (<*>)
and (>>=)
/(=<<)
take a binary function and a unary function, and constrain one of the two arguments of the former to be determined from the other one, via the latter. After all, we know that for the function applicative/monad,
f <*> g = \x -> f x (g x)
f =<< g = \x -> f (g x) x
And they look so strikingly similar (or symmetric, if you want), that I can't help but think of the question in the title.
As regards monads being "more powerful" than applicative functors, in the hardcopy of LYAH's For a Few Monads More chapter, the following is stated:
[…]
join
cannot be implemented by just using the functions that functors and applicatives provide.
i.e. join
can't be implemented in terms of (<*>)
, pure
, and fmap
.
But what about the function applicative/mondad I mentioned above?
I know that join === (>>= id)
, and that for the function monad that boils down to \f x -> f x x
, i.e. a binary function is made unary by feeding the one argument of the latter as both arguments of the former.
Can I express it in terms of (<*>)
? Well, actually I think I can: isn't flip ($) <*> f === join f
correct? Isn't flip ($) <*> f
an implementation of join
which does without (>>=)
/(=<<)
and return
?
However, thinking about the list applicative/monad, I can express join
without explicitly using (=<<)
/(>>=)
and return
(and not even (<*>)
, fwiw): join = concat
; so probably also the implementation join f = flip ($) <*> f
is kind of a trick that doesn't really show if I'm relying just on Applicative
or also on Monad
.