

Monoids without tears (2014) - ZenoArrow
http://fsharpforfunandprofit.com/posts/monoids-without-tears/

======
zak_mc_kracken
Did you ever realize that there is a similarity between addition (+) and zero
(0) and multiplication (x) and 1? Can you guess what it is?

If you add something to zero, you get that same thing.

If you multiply something by one, you get that same thing.

That's what a monoid is: the generalization of the idea that if you can find
an operator on a certain set (+ and x) and a special member of that set (0 and
1) that obey a few simple laws, then that thing is a monoid.

So we have identified two monoids: (Integer, +, 0) and (Integer, x, 1). Of
course, this works with Floats and a few other number-based types.

I'll give you another example of a monoid: (String, append, ""), because if
you add the empty string to a string, you get that same string back.

Now monads are a different topic. They are a monoid but understanding them
requires a little bit more background, so I'll stop there.

~~~
jfarmer
Other "every day" monoids:

    
    
        - (Array, concat, [])
        - (Floating point numbers, min, +Infinity)
        - (Floating point numbers, max, -Infinity)
        - (Boolean, AND, true)
        - (Boolean, OR, false)
        - (Subsets of set S, union, {})
        - (Subsets of set S, intersection, S)
        - (Functions of type S → S, composition, the identity function)
    

You'll often see folks writing functions from Strings to Strings but returning
_null_ or the like in the "empty" case instead of an empty String. Having them
instead return the "identity" element of the relevant monoid will always
result in a simpler, more composable interface.

~~~
rahimnathwani
> Having them instead return the "identity" element of the relevant monoid
> will always result in a simpler, more composable interface.

But there may be more than one relevant monoid, and thereby more than one
identity element.

In the case of a function which returns an integer, should I return the
multiplicative identity, or the additive one?

~~~
jfarmer
For a given problem, there's often some natural monoidal structure underneath
the hood even if the operations aren't explicitly part of the type signature.

For example, it's "natural" for the sum of an empty list to be 0 but the
product of an empty list to be 1. Why? So that the "hidden homomorphism" is
preserved (here ++ is list concatenation):

    
    
            sum(listA ++ listB) == sum(listA) + list(listB)
        product(listA ++ listB) == product(listA) * product(listB)
    

For similar reasons, given some predicate P is some predicate, the any? should
return false for an empty list and all? should return true so that the
following hold:

    
    
        all?(P, listA ++ listB) == all?(P, listA) && all?(P, listB)
        any?(P, listA ++ listB) == any?(P, listA) || any?(P, listB)
    

Behind it all we're not only transforming values of TypeA into values of TypeB
, we're doing it in a way that respects some underlying monoidal structure.

If you want to think of it in a more programmer-centric way, any time you have
an operation that could be as a fold[1] there is an underlying monoidal
structure. Monoids permit folding, folding implies the existence of some
monoid.

[1]: [http://en.wikipedia.org/wiki/Fold_(higher-
order_function)](http://en.wikipedia.org/wiki/Fold_\(higher-order_function\))

~~~
siddboots
There's a typo in the first line of your first example.

    
    
        list(listB)
    

should read

    
    
        sum(listB)

~~~
jfarmer
Indeed!

------
ZenoArrow
This is the first 'F# For Fun and Profit' article I've read, I was very
impressed with how the author (Scott Wlaschin?) breaks the subject of monoids
down so clearly, something tells me that the author will be helping me out a
lot in the coming months.

~~~
gavinpc
Monoid != Monad

There seems to be some confusion about which one is confusing. The hardest
part of understanding monoids is accepting that yes, that's all there is to
it. The fuss is about the other one.

~~~
ZenoArrow
Yes, I know that a monoid and a monad are two different terms, there's no
confusion.

However, despite monoids being relatively simple, my first introduction to
monoids was this...

[http://gettingsharper.de/2015/03/03/understanding-monoids-
us...](http://gettingsharper.de/2015/03/03/understanding-monoids-using-f/)

... which I didn't find beginner friendly. YMMV.

~~~
gavinpc
But what is the use of understanding monoids, other than as a step towards
understanding monads?

No criticism... I read all of these submissions. But the ones which only cover
monoids [0] leave me wondering, Okay, now what?

So I guess the confusion is mine.

[0] Other than to say that monads are "very different things".

~~~
ZenoArrow
> "But what is the use of understanding monoids, other than as a step towards
> understanding monads?"

I'm sorry, but I don't follow. It's just terminology for communicating more
efficiently with other programmers (and mathematicians, in this case). They're
both a group of ideas with a label. Why would one group only serve to
introduce the second group?

~~~
gavinpc
You're completely right — I stand corrected. The OP covers practical usages at
the end of the piece, as well as in a follow-up piece for that sole purpose.
Thanks.

