A great resource for information on common typeclasses in Haskell is the typeclassopedia. We recommend reading that document, and following up here for additional pointers.
Applicativewasn't a superclass of
Monadin the past
Semigroupwasn't a superclass of
Monoidin the past
fmap :: (a -> b) -> (f a -> f b)
fmap id == id
fmap (g . h) == fmap g . fmap h
pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
fmap :: (a -> b) -> f a -> f b (<*>) :: f (a -> b) -> f a -> f b
Also note that you can define
fmap g x = pure g <*> x
pure id <*> x == x
pure f <*> pure x == pure (f x)
u <*> pure y == pure ($ y) <*> u
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w
(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b
fmap :: (a -> b) -> f a -> f b (<*>) :: f (a -> b) -> f a -> f b (=<<) :: (a -> m b) -> m a -> m b
pure a >>= f == f a
m >>= pure == m
m >>= (\x -> f x >>= g) == (m >>= f) >>= g
And we can define:
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
And then restate these laws as:
f <=< pure == f pure <=< f == f (h <=< g) <=< f == h <=< (g <=< f)
Which are the same as the category laws:
f . id == f id . f == f (h . g) . f == h . (g . f)
Semigroup defines a binary, associative operator.
(<>) :: a -> a -> a
(x <> y) <> z == x <> (y <> z)
Monoid is a subclass of
Semigroup, and adds an identity to
mempty :: a
The laws are the same again as
Monad and categories!
x <> mempty == x mempty <> x == x (x <> y) <> z == x <> (y <> z)
More worked explanation:
Semigroup is a typeclass that provides a single binary, associative operator.
For example, for integers,
* are both valid
For lists, appending two lists forms a
Monoid builds on
Semigroup, but adds in an identity, where it follows the law that applying that binary operator as either the left or right value to the identity is a no-op
In other words:
0 + x = x,
x + 0 = x, and
(a + b) + c = a + (b + c).
(<>) = (+) and
mempty = 0 forms a valid
Monoid pair of instances.
Some things are a
Semigroup, but not a Monoid.
A simple example: a non-empty list. While you can append together two non-empty lists, there's no identity value you can come up with where the identity laws hold.
That's all the technical definition. Intuition:
Monoid let you define a way to slam data together!
EXERCISE Write a data type for calculating the average of a bunch of values. The data type will need to have two fields: one to keep the running sum, one the running total. Then write
Monoid instances that Do The Right Thing, define an
average function that calculates the average from these two fields, and you're done. Try using
fold (part of the
Foldable typeclass we'll cover next) to summarize a list of values.
foldMap :: Monoid m => (a -> m) -> f a -> m
Vectorthat folds left-to-right or right-to-left
lengthof tuples and other things considered surprising/wrong by many
mapM, but works for
forM, but for
See start of section