Lomig

Posted on

# Monads explained to my team β Part 1: Monoids

βHey, for our next talk about growing and discovering new ways of thinking about programming, I wondered if you would be interested in learning about Monads?β, I asked on our Slack Channel.

βSure, don't hesitate to share an article before we can discuss it together!β my CTO answered.

Problem is: for every batch of 20 developers trying to learn about monads, 15 will abandon because of awful tutorials, 3 will succeed quietly, hurt by awful tutorials, and 2 will succeed but will decide they could do better than the awful and confusing tutorials they found βΒ to write even worse tutorials of their own.

Guess what kind of people I am?

So, sure. Let's do that: an article, or rather a series of articles taking us from the basic theory to a Ruby implementation of the concept.

The first two articles are not mandatory: it's tradition to explain monads through a diabolical mathematical description, and I feel I also have to make this explanation accessible, but it surely will be one of the reason why my own tutorial will be even worse than the cursed ones before me!

Β Β

## Fancy words for simple concepts

Developers uses Monoids everyday unknowingly, so let's figure out what this is all about.

Β Β

## A little bit of Math

### Composition

Let's look at this piece of code:

``````42 + 58 #=> 100
``````

What do we see? Two things of the same kind combined together by an operator produce another thing of the same kind.

When combining two `Int` with the `+` operator, we will get an `Int`.

``````11 * 25 #=> 275
``````

Again! A thing, combined with another thing of the same kind gives us a thing of the same kind.

There are a lot of examples built-in in Ruby:

``````"my " + "string" #=> "my string"
[1, 3] + [2, 8] #=> [1, 3, 2, 8]
{ a: :foo, b: :bar }.merge({ fizz: :buzz }) #=> { a: :foo, b: :bar, fizz: :buzz }
4 - 16 #=> -12
``````

It does not work for every operation though: dividing an integer by another one can result in a non-integer number.

Β Β

#### Useless bit of information

In Mathematics, when an operation between two things give the same thing, we call this operation a closed dyadic/binary operation for those things. `+` is a closed dyadic operation for `integers`.

Β Β

### Association

We can see that some types and operations have another interesting property:

``````"a"              # is a String ("a")
"a"  + "b"       # is a String ("ab")
"ab" + "c"       # is a String ("abc")
"a"  + "bc"      # is a String ("abc")
"a"  + "b" + "c" # is a String too! ("abc")
# [...]
("a" + "b") + "c" == "a" + ("b" + "c") #=> true

1 + 2 + 3 + 4 == (1 + 2) + (3 + 4)
== 1 + (2 + 3) + 4
== ((1 + 2) + 3) + 4
``````

Here again, it does not work for every types/operations β integers and subtraction for example:

``````(1 - 2) - 3 #=> -1 - 3 == -4
1 - (2 - 3) #=> 1 - -1 == 2

(1 - 2) - 3 != 1 - (2 - 3)
``````

Β Β

#### Useless bit of information

In Mathematics, when rearranging the parentheses in an expression of things and an operation will not change the result, we call this operation an associative operation for those things. `+` is an associative operation for `integers`.

Β Β

### Special elements

There is a very special String that has a very interesting property : it changes nothing in a concatenation.

``````"" + "my string" == "my string" #=> true
"my string" + "" == "my string" #=> true
``````

In the same way, we can find the same kind of special elements for other types and operations:

``````0 + 4 == 4                           #=> true
215 * 1 == 215                       #=> true
[:foo, :bar] + [] == [:foo, :bar]    #=> true
{ a: :foo }.merge({}) == { a: :foo } #=> true
``````

Β Β

#### Useless bit of information

In Mathematics, an element that leaves every element of a set unchanged through an operation is called the identity element. `0` is the identity element of `+` for `integers`.

Β Β

And that's it, we have all what we need to define a monoid!

A monoid is a set and an operation where the operation is a closed dyadic operation, where the operation is associative, and where an identity element exists.

• (`Integer`, +) is a monoid
• (`Float`, +) is a monoid
• (`Array`, #concat) is a monoid
• β¦

Β Β

## As a Rubyist, why do I care?

• The first rule of a monoid (we call it closure in computer science instead of closed dyadic operation) is linked to another functional concept already implemented in Ruby: monoids are reducible:
``````["c", "o", "o", "l"].reduce(&:+)    #=> "cool"
[2, 5, 7].reduce(&:*)               #=> 70
[[1, 2], [3], [4]].reduce(&:concat) #=> [1, 2, 3, 4]
``````
• The second rule, associativity makes those chained operations optimization-ready: Divide & Conquer strategies, parallel threads, incremental accumulationβ¦

• The third rule, the identity, gives you an initial value when the data is empty or does not exist yet.

Β Β