There are a number of cases in the base
package where the same
functionality exists under two different names. This can occur for a
number of different reasons, but most commonly it's either:
- One version is more general than the other via some typeclass
- A historical name has lingered on
The presence of identical (or nearly identical) functionality under
different names can lead to confusion when reading code. The purpose
of this page is to point out these occurrences to bypass this
confusion.
concat, mconcat and fold
GHC.OldList.concat :: [[a]] -> [a]
Prelude.concat :: Foldable t => t [a] -> [a]
mconcat :: Monoid a => [a] -> a
fold :: (Foldable t, Monoid a) => t a -> a
All four of these functions allow us to collapse down a sequence of
values into a single value. The most specific is GHC.OldList.concat
:
given a list of lists, it combines all of these lists together into a
single list. The most general is fold
, which leverages two
typeclasses:
- Instead of requiring that the containers be a list, it leverages the
Foldable
typeclass to work with many more data structures
- Instead of requiring that the values being combined be lists, it
generalizes to any instance of
Monoid
concatMap and foldMap
GHC.OldList.concatMap :: (a -> [b]) -> [a] -> [b]
Prelude.concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
foldMap :: (Foldable t, Monoid b) => (a -> b) -> t a -> b
This is very similar to the concat
/mconcat
/fold
breakdown
above. We can generalize from lists to instances of Foldable
and
Monoid
.
*> and >>
(*>) :: Applicative f => f a -> f b -> f b
(>>) :: Monad m => m a -> m b -> m b
The only difference between these two is Applicative
vs
Monad
. This is a holdover from the days when Applicative
was not a
superclass of Monad
.
pure and return
pure :: Applicative f => a -> f a
return :: Monad m => a -> m a
return
is pure
specialized to Monad
, relevant for the same
superclass reason above.
map, fmap and liftM
map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
liftM :: (Monad m) => (a -> b) -> m a -> m b
map
is specialized to just lists, while fmap
is generalized to all
Functor
s. Like *>
vs >>
, the presence of liftM
is just a
holdover from the days when Functor
was not a superclass of Monad
.
traverse_ and mapM_
traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f ()
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
mapM_
is traverse_
specialized to Monad
, relevant for the same
superclass reason above.
sequenceA_ and sequence_
sequenceA_ :: (Foldable t, Applicative f) => t (f a) -> f ()
sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
Same Monad
/Applicative
specialization.
traverse and mapM
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
Same Monad
/Applicative
specialization.
sequenceA and sequence
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
Same Monad
/Applicative
specialization.
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)
forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
Same Monad
/Applicative
specialization.
<>, ++ and mappend
(++) :: [a] -> [a] -> [a]
Data.Semigroup.(<>) :: Semigroup a => a -> a -> a
mappend :: Monoid m => m -> m -> m
++
is simply <>
and mappend
specialized to lists. mappend
should be the
same as <>
in all cases.
Note: historically, Semigroup
was not a superclass of Monoid
, resulting in
<>
and mappend
having potentially different implementations. That no longer
applies.