The signature of sequence is
sequence :: Monad m => t (m a) -> m (t a)
But we can implement it as
sequence = traverse id
requiring m to be just Applicative. If monads are applicatives then why bother having this constraint on type level?
The signature of sequence is
sequence :: Monad m => t (m a) -> m (t a)
But we can implement it as
sequence = traverse id
requiring m to be just Applicative. If monads are applicatives then why bother having this constraint on type level?
There are many functions in Haskell that are equivalent but distinct because Applicative (resp. Functor) didn’t use to be a superclass of Monad. For example:
return vs. pure
ap vs. <*>
liftM vs. liftA vs. fmap
liftM2, liftM3, &c. vs. liftA2, liftA3, &c.
mapM/forM vs. traverse/for
mapM_/forM_ vs. traverse_/for_
sequence vs. sequenceA
mzero & mplus (from MonadPlus) vs. empty & <|> (from Alternative)
The old functions with their original Monad signatures are still present, but in new code, since the Applicative–Monad Proposal (AMP) was implemented, you can always use the Applicative versions because they’re slightly more general—that is, you can always replace return with pure, but not vice versa.