Given:
Applicative m, Monad m => mf :: m (a -> b), ma :: m a
it seems to be considered a law that:
mf <*> ma ==
Well, I'm not terribly satisfied with the answers given so far, but I think the comments attached to them are a bit more compelling. So I'll summarize here:
I think there's only one sensible Functor
instance that follows from Applicative
:
fmap f fa = pure f <*> fa
Assuming that's unique, it makes sense that Functor
should be a superclass of Applicative
, with that law. Likewise, I think there's only one sensible Functor
instance that follows from Monad
:
fmap f fa = fa >>= return . f
So again, it makes sense that Functor
should be a superclass of Monad
. The objection I had (and, really, still have) is that there are two sensible Applicative
instances that follow from Monad
and, in some specific instances, even more that are lawful; so why mandate one?
pigworker (first author on the original Applicative paper) writes:
"Of course it doesn't follow. It's a choice."
(on twitter): "do-notation is unjust punishment for working in a monad; we deserve applicative notation"
duplode similarly writes:
"... it is fair to say that
pure === return
and(<*>) === ap
aren't laws in the strong sense that e.g. the monad laws are so ...""On the
LeftA
/RightA
idea: there are comparable cases elsewhere in the standard libraries (e.g.Sum
andProduct
inData.Monoid
). The problem of doing the same withApplicative
is that the power-to-weight relation is too low to justify the extra precision/flexibility. The newtypes would make applicative style a lot less pleasant to use."
So, I'm happy to see that choice stated explicitly, justified by the simple reasoning that it makes the most common cases easier.
Among other things, you ask why is the Functor-Applicative-Monad
proposal a good thing. One reason is because the lack of unity means there is a lot of duplication of API. Consider the standard Control.Monad
module. The following are the functions in that module that essentially use the Monad
(there are none for MonadPlus
) constraint:
(>>=) fail (=<<) (>=>) (<=<) join foldM foldM_
The following are the functions in that module where a Monad
/MonadPlus
constraint could as far as I can tell easily be relaxed to Applicative
/Alternative
:
(>>) return mzero mplus mapM mapM_ forM forM_ sequence sequence_ forever
msum filterM mapAndUnzipM zipWithM zipWithM_ replicateM replicateM_ guard
when unless liftM liftM2 liftM3 liftM4 liftM5 ap
Many of the latter group do have Applicative
or Alternative
versions, in either Control.Applicative
, Data.Foldable
or Data.Traversable
– but why need to learn all that duplication in the first place?
and in my own (perhaps mistaken) intuition, given
pure f <*> ma <*> mb
, there needn't be any predetermined sequencing since none of the values depend on each other.
The values don't, but the effects do. (<*>) :: t (a -> b) -> t a -> t b
means that you have to somehow combine the effects of the arguments in order to get the overall effects. Whether the combination will be commutative or not depends on how the instance is defined. For example, the instance for Maybe
is commutative, while the default, "cross join" instance for lists isn't. Therefore, there are cases in which you can't avoid imposing some order.
What are the laws, if any, relating Monad and Applicative?
While it is fair to say that pure === return
and (<*>) === ap
(quoting Control.Applicative) aren't laws in the strong sense that e.g. the monad laws are so, they help keeping the instances unsurprising. Given that every Monad
gives rise to an instance of Applicative
(actually two instances, as you point out), it is natural that the actual instance of Applicative
matches what Monad
gives us. As for the left-to-right convention, following the order of ap and liftM2 (which already existed back when Applicative
was introduced, and which mirror the order imposed by (>>=)
) was a sensible decision. (Note that, if we ignored for a moment how much (>>=)
matters in practice, the opposite choice would be defensible as well, as it would make (<*>)
and (=<<)
, which have analogous types, sequence effects in the same order.)
Does GHC or any other tool perform code transformations that assume/require this law to be true?
That sounds very unlikely given that Applicative
isn't even a superclass of Monad
(yet). These "laws", however, allow readers of the code to make the transformations, which matters just as much.
N.B.: If you need to reverse the sequencing of effects in an Applicative
instance, there is Control.Applicative.Backwards, as Gabriel Gonzalez has pointed out. Also, (<**>) flips the arguments but still sequences effects from left to right, so it can also be used to reverse sequencing. Similarly, (<*)
is not flip (*>)
, as both sequence effects from left to right.
Just for the record, the answer to the question in the title is: consider
sequenceA :: Applicative f, Traversable t => t (f a) -> f (t a)
join :: Monad m => m (m a) -> m a
What is the type of join . sequenceA
?
Monad m, Traversable m => m (m a) -> m a
Applicative m, Monad m, Traversable m => m (m a) -> m a
Granted, join . sequenceA
is a contrived situation, but there are certainly cases where you need a monad, but you'd also like to use the Applicative
operations <*>
, *>
, <*
, <**>
, etc. Then:
Applicative
names is (IMHO) nicer than those of the traditional monad operations.ap
, >>
, <<
, etc., is annoying ("oh, you can't use <*>
there, that's a Monad
not an Applicative
"; "oh, you have to use <*>
there, that's an Applicative
not a Monad
").>>
and *>
do different things, then you can't actually use the Applicative
syntax, because it'll do something you don't expect.So, pragmatically, having an Applicative
for every Monad
which is compatible with it (in the (<*>) = ap
sense) is a really, really good idea.