April 24, 2016 / by Kim Hogeling / Web developer / @kimhogeling
Scott Wlaschin is an IT architect, developer, F# trainer and consultant. He created the website fsharpforfunandprofit.com and is writing a book called understanding functional programming. Mr Wlaschin knows how to explain code design in an easy to follow and enjoyable way. Most of his talks that I have seen are about functional programming, secure code and good code design.
So, what is a monoid anyway?
You can skip this section, if you watched Scott Wlaschin’s Talk.
The following three rules apply to monoids:
- Closure: The result of combining two things is always another one of the things. This means that the input and output need to be of the same type.
- Associativity: When combining more than two things, which pairwise combination you do first doesn’t matter.
- Identity element: There is a special thing called “zero” such that when you combine any thing with “zero” you get the original thing back. Some examples:
The code in this section is written in JS. The practical example further below is written in F#, JS and PHP.
This is a monoid for numbers because the 3 rules apply:
add(add(1, 2), add(3, 4))equals
add(1, add(add(2, 3), 4))
- Identity element:
add(1, 0)also equals
Substract is not a monoid for numbers because 2 out of 3 rules do not apply:
substract(substract(1, 2), substract(3, 4))does not equal
substract(1, substract(substract(2, 3), 4))(
0does not equal
- Identity element: e.g.
0is not an identity element, because
substract(1, 0)does not equal
To use the
concatenate lambda as a monoid for strings, the list of numbers is first mapped to a list of strings.
Because lambdas are so easy to pass around without any side effects, we can make a list out of them. This list can be mapped to the results of each reduce result for each monoid.
concatenate needs different input than numbers, it is not included in this list. Notice, that the values are not passed from lambda to lambda. This is not a chain, but just a simple list. To create a chain the amount of inputs need to match the amount of outputs. That is not the case for our current lambdas, because they accept two arguments and return one value.
Practical example: Sum of products in a wishlist
Let’s use a more realistic example. Instead of taking Scott Wlaschin’s example, I thought of one, which could be useful for the shopping24 wishlist. This wishlist contains the products that are “starred” by the visitor. I want to sum the prices and shipping costs of the products. This is achieved by combining the wishlist products with help of F#
Array.prototype.reduce and PHP
array_reduce and a monoid called
I find this solution slick and easy to read. Having
pairAdd to be a monoid for any object with the keys
shipping is simple and doesn’t cause any side effects.
In contrast, the common solution would be to have a Wishlist class which would have a list of products and a method to sum the prices by iterating over the products. But that would create a lot of overhead and would also require noisy variables like
Anyway, I’m sure I’ll watch more of Scott Wlaschin’s talks. Currently (2016-04-24) Vimeo has 9 uploads of each about an hour. If you care about good code design and security, I recommend Designing with capabilities for fun and profit. So grab some Mate and Nachos and enjoy!