You are probably already aware of monoids (via the Monoid
type class), since they come up quite often in programming. We’ll just quickly remind ourselves about what makes something a monoid and cover a few examples, but in a slightly more mathematically-oriented way. The main aim of this section is to make you a bit more comfortable about mathematical ideas and notations by using them to describe an idea which you are hopefully already familiar with. Another purpose of this section is to prepare you for the next section, in which we will talk about a specific kind of monoid which turns out to be rather important.
Here are a few rules about how adding integers together works:
Here are a few more rules about how multiplying integers works:
Now, instead of integers, we will consider a different set: the set of truth-values \(\{T, F\}\). This set corresponds to the Boolean
type in PureScript. Here are some rules for how the “logical and” operation \((\land)\) works on truth-values:
p && true
.Hopefully a pattern will be starting to emerge: in each case, we have a set, an operation which gives us a way of combining two elements of that set to produce another element of the same set, and some rules that the operation should satisfy. The general definition of a monoid is as follows:
A monoid is a set \(M\), together with an operation \(*\), such that the following laws hold:
Looking back to the examples above, we have the monoids of:
The operation \(*\) corresponds to append
in PureScript, and that the identity element (conventionally written \(e\)) corresponds to mempty
in PureScript.
We will now look at a few non-examples of monoids and talk about why they fail to be monoids.
First, if we take the set of natural numbers which are less than 4, that is \(\{0, 1, 2, 3\}\), and take addition as the operation, this fails to be a monoid because it does not satisfy closure. To show this we need to find a pair of elements such that their sum is not in the set. One such choice is \(3 + 1\), which of course equals \(4\), which is not in the set. We say that a set is closed under an operation if performing that operation on two elements of the set always produces another element of the set; this is where the name “closure” comes from.
An example of something failing to be a monoid because the operation is not associative could be the set of floating point number values under addition. For example, try (0.1 + 0.2) + 0.3
in a console, and compare the result to 0.1 + (0.2 + 0.3)
.
An example of something failing to be a monoid because of a lack of an identity element could be the set of even numbers under multiplication. The first two laws are satisfied, but since 1 is not an even number, we don’t have an identity element.
A brief interlude on notation: if we want to refer to a specific monoid, we write it as a pair where the first element is the set and the second is the operation. For example, the monoid of integers under addition is written as \((\mathbb{Z}, +)\). If it is clear from context which operation we are talking about, we often omit the operation and just write the set, e.g. we might simply say \(\mathbb{Z}\) is a monoid.
Exercise 2.1. Consider the set of natural numbers together with the operation of subtraction: \((\mathbb{N}, -)\). This is not a monoid. Can you say which of the three laws fail to hold (it might be more than one) and why?
Exercise 2.2. The set of rational numbers is the set of numbers which can be written as the ratio of two integers \(\frac{a}{b}\). There is a short-hand notation for this set too: \(\mathbb{Q}\) (for “quotient”). Show that \((\mathbb{Q}, +)\) is a monoid by checking each of the three laws. What is the identity element?
Uniqueness of identity elements¶Exercise 2.3. (Harder) Prove that a monoid can only have one identity element. To do this, first suppose that you have two elements of some monoid; call them, say, \(e\) and \(e'\), and then show that if they are both identity elements then they must be equal to each other. Be careful here: it’s not enough to take one specific example of a monoid and show that it only has one identity element. You have to construct an argument which will work for any monoid, which means you aren’t allowed to assume anything beyond what is in the definition of a monoid.
Note
In general, if we want to prove that there is a unique element of some set which has some particular property, we do this by taking two arbitrary elements of the set, assuming that they both have this property, and then showing that they must be equal.
Since monoids have a unique identity element, we can talk about the identity element of a monoid, rather than just an identity element.
Some more examples¶Consider the set \(\{e\}\), which contains precisely one element, \(e\). We can define an operation \(*\) on this set as follows:
\[e * e = e\]
That’s all we need to do to define \(*\), because there are no other possible values to consider. Then, \(\{e\}\) is a monoid. It’s not very interesting which is why it gets called the trivial monoid. This corresponds exactly to the Unit
type in PureScript; the Unit
type has precisely this Monoid
instance too.
Let \(X\) be any set, and consider the set of functions from \(X\) to \(X\), which we denote by \(\mathrm{Maps}(X, X)\). If we take function composition \(\circ\) as our operation, we have a monoid \((\mathrm{Maps}(X, X), \circ)\). Let’s check this:
This may seem a bit abstract, so here’s a concrete example. We will take the set \(X\) to be the set \(\{A, B\}\) which contains just two elements. (The elements \(A\) and \(B\) don’t really mean anything here, they’re just symbols.) Then there are four functions from \(X\) to \(X\):
In PureScript:
e :: X -> X e x = x -- or simply e = identity fA :: X -> X fA _ = A -- or simply f1 = const A fB :: X -> X fB _ = B -- or simply f2 = const B fSwap :: X -> X fSwap A = B fSwap B = A
Here are a few examples of how the monoid operation works in this monoid:
\[ \begin{align}\begin{aligned}f_A \circ f_B = f_A\\f_B \circ f_{swap} = f_B\\f_{swap} \circ f_{swap} = e\end{aligned}\end{align} \]
(check that you agree).
This monoid is implemented in PureScript in the module Data.Monoid.Endo
, which is part of the purescript-prelude
library.
We now move on to the last example of a monoid in this chapter:
Exercise 2.4. Let \((M, *)\) be any monoid, and let \(X\) be any set. Define an operation \(\star\) on the set \(\mathrm{Maps}(X, M)\) — that is, the set of functions from \(X\) to \(M\) — as follows:
\[f \star g = x \mapsto f(x) * g(x)\]
On notation: the arrow (\(\mapsto\)) can be read “maps to”. The mathematical notation \(x \mapsto x + 4\) means essentially the same thing as the PureScript code \x -> x + 4
, that is, it denotes a function.
That is, the star product \(\star\) of two functions \(f\) and \(g\) is a new function which applies both \(f\) and \(g\) to its argument, and then combines the results using the monoid operation \(*\) from the monoid \(M\). Prove that \((\mathrm{Maps}(X, M), \star)\) is a monoid; what is the identity element?
The monoid in this exercise is also implemented in PureScript’s Prelude
; in fact it is the default Monoid
instance for functions, written as Monoid b => Monoid (a -> b)
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4