Monoids
You may find that life becomes much easier when you realize that you can stand on the shoulders of giants and use common abstractions and libraries created to use them. To this end, this question is mainly related to monoids (for more details see related questions below), and the corresponding library is called scalaz .
Using scalaz FP, this is true:
def add(a: Option[Int], b: Option[Int]) = ~(a |+| b)
The more this works on any M monoid:
def add[M: Monoid](a: Option[M], b: Option[M]) = ~(a |+| b)
Even more useful, it works with any number of them placed inside the Foldable
container:
def add[M: Monoid, F: Foldable](as: F[Option[M]]) = ~as.asMA.sum
Note that some pretty useful monoids besides the obvious Int
, String
, Boolean
:
Map[A, B: Monoid]
A => (B: Monoid)
Option[A: Monoid]
In fact, it is hardly worth worrying about extracting your own method:
scala> some(some(some(1)))
Some related questions
Q. What is a monoid?
A monoid is a type M
for which there is an associative binary operation (M, M) => M
and an identity I
such that mplus(m, I) == m == mplus(I, m)
for all M
type M
Q. What is |+|
?
This is just an abridged version (or ASCII madness, ymmv) for the mplus
binary operation
Q. What is ~
?
This is a unary operator meaning "or identity", which is modified (using scala implicit conversions) with the scalaz library on Option[M]
if M
is a monoid. Obviously, a non-empty option returns its contents; an empty option is replaced by a monoid identifier.
Q. What is asMA.sum
?
A Foldable
is basically a data structure that can be folded (e.g. foldLeft
). Recall that foldLeft
takes an initial value and an operation for composing sequential calculations. In the case of summing the monoid, the initial value is the identifier I
, and the operation is mplus
. Therefore, you can call asMA.sum
on a Foldable[M : Monoid]
. You may need to use asMA
due to a name clash with the standard sum
library method.
Some links
- Slides and Talk videos which give practical examples of the use of monoids in the wild.