Monoids have since been in existence. Although mathematics made them popular, monoids have become an important concept in functional programming.
If you make a quick search on monoids in your browser, everything that would come up on your first search page is probably mathematics jargon like algebraic and how monoids are a big deal with math stuff.
Well in this article, as you would expect, we would be discussing monoids from the angle of functional programming. By the end of this article, you would have understood monoids in functional programming, why they are important and you would appreciate them because they already exist all around you.
I hope this would be the last article you ever have to read about monoids. Let's get to work.
You know monoids
Yes, you do ๐. Funny enough monoids are all around us.
We use them now and then. They are one of the first concepts taught to every programming language beginner, just that they were abstracted until now.
A very good example is string concatenation. Let's take JavaScript for example. To concatenate strings the key used is the plus symbol, "+". If one would concatenate "sekx" and "Kelvin" would be done like below.
"sekx" + " Kelvin" // returns "sekx Kelvin"
The fun part is we can concatenate three words together like "Kelvin", "sekx" and "Ibadan". See how it is done below.
"Kelvin" + " sekx" + " Ibadan //=> "Kelvin sekx Ibadan"
You might have never noticed this, but JavaScript doesn't combine everything all at once. It first combined two words and combined the result with the last word.
("Kelvin " + ("sekx" + " Ibadan"))
Other examples of monoids include
- map merge (or array concatenation).
- addition and subtraction
- AND/OR
- Math.min/max and many more ๐
Now that I've been able to convince you already know monoids, let's talk about what makes these examples monoids. I mean why are they monoids?
Characteristics of a monoid
They all are binary operations that take an associative approach
Monoids are binary operations since they take two arguments per time, make an operation with both arguments, and return a new element as a result of the operation.
2 + 3 //=> 5, a new element
[2, 4, "sekx"]
.concat(["market"]) //=> [2, 4, "sekx", "market"]
Sometimes this doesn't look obvious but that is the first thing to notice about them. When it happens that you don't use a second argument, they fall back to an identity.
Math.min(5) //=> 5
What associativity (also associative approach) means is when given more than two arguments the direction at which the binary operations should take precedence from (usually for JavaScript it's left to right) can be either "left to right" or "right to left". You can sometimes use the parentheses or brackets to stipulate the place of precedence.
Associativity states that if the precedence is influenced from "right to left" instead of "left to right", it should not affect the result of the operation. Too much grammar already ๐, see the codes below for a summary.
// Associativity
(a + b) + c = a + (b + c)
/**Left to right*/
(2 + 5)+ 7 //=> 14
/**Right to left */
2 + (5+ 7) //=> 14
// Irrespective of the direction
// of precedence, the
// result is the same
They all have an identity that is used in place when only one argument is given.
For example, the identity of
- string concatenation is an empty string,
''
, - Identity for numbers operation is 0
- The identity for Math.min is positive Infinity and for Math.max is negative infinity.
Math.min(4) // 4
// Behind the scene the second
// argument is replaced
// with an identity
Math.min(Infinity, 4) // 4
Math.min(4, Infinity) //4
// Also you could have seen ๐ค the
// associativity rule in action above
Math.min(Infinity, 4) == Math.min(4, Infinity) // true
- The identity for array concatenation is an empty array.
Bonus, this stack exchange answer is a good explanation of identity.
The inputs and output are all of the same types
This is might not have caught your eyes but if you make a rewind to all the examples of monoids given above, you would realize the type of the arguments is the same as the result. For JavaScript, if the types aren't the same, it forces them to be.
// string + string = string
"I " + "love you" // "I love you"
// it forces the second argument
// into a string
"country " + 4 // "country 4"
// number, number = number
Math.min(3, 6) // 3
// it forces the string to a number
Math.max(30, "kelvin") // NaN: the typeof NaN is a "number"
Those are the three characteristics of a monoid and I hope this article has helped you demystify what monoids are. The beauty of monoids begins when we start to implement this pattern in our code and functions and I would admonish that you go and implement this pattern in your next function.
Monoids are particularly important when one creates combining functions or what we call composes.