4 ms·
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
by zak_mc_kracken 12y ago
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 12y agoOther "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 12y ago> 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 12y agoFor 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)