Before talking about Monoids and Semigroups, you first have to understand what “an algebra”(in the context of Functional Programming) is. From Mathematics, Algebra is a tool used to manipulate symbols. We really don’t care what those symbols contain; instead, what we care about is some of the laws you have to follow. In the Functional Programming universe, an algebra is an operation and the set it can operate on. Both a Monoid and Semigroup are algebras.
A Monoid is an operation which meets the following properties:
- It has an identity. An identity function always returns the same value used as its argument. The id of the sum operation is 0 and the id of the product is 1. A Monoid has both the left and right identity.
- It is associative. Associativity means that an operation can be grouped in any order e.g. : (a + b) + c == a + (b + c)
- It is a binary operator. A binary operator only takes 2 arguments.
A Semigroup is similar to the Monoid; the only difference being that it does not have to meet the identity requirement. A Monoid can be considered a subset of the Semigroup set.
In Haskell, the Monoid is defined in its own typeclass as:
class Monoid m where mempty :: m mappend :: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty
When a specific type implements the Monoid typeclass, it will automatically be reduce-able. You can also be able to use the infix operator `<>` which behaves in a similar way to `mappend`. In Haskell, the most common case of a type that has an instance of the Monoid typeclass is the List.
mappend [1, 2, 3] [4, 5, 6] [1, 2, 3] <> [4, 5, 6] [1, 2, 3] ++ [4, 5, 6] -- They all print the same thing: -- [1, 2, 3, 4, 5, 6]