View and edit this tutorial on Github | Discuss on Reddit | Tweet this
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:
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.
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:
Foldable typeclass to work with many more data structuresMonoidGHC.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.
(*>) :: 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 :: 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 :: (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
Functors. Like *> vs >>, the presence of liftM is just a
holdover from the days when Functor was not a superclass of Monad.
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_ :: (Foldable t, Applicative f) => t (f a) -> f () sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
Same Monad/Applicative specialization.
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 :: (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.
(++) :: [a] -> [a] -> [a] Data.Semigroup.(<>) :: Semigroup a => a -> a -> a Data.Monoid.(<>) :: Monoid m => m -> m -> m mappend :: Monoid m => m -> m -> m
The presence of two different <> operators is purely a historical
accident, caused by the fact that Semigroup is not (yet) a
superclass of Monoid. The functionality for each version of the
operator should be identical. In the case of Monoid, the <>
operator is identical to the mappend function.
++ is simply <> and mappend specialized to lists.