In scala, how do I define addition over two Option arguments? Just to be specific, let\'s say they\'re wrappers for Int types (I\'m actually working with maps of do
You might find life becomes a lot easier when you realize that you can stand on the shoulders of giants and take advantage of common abstractions and the libraries built to use them. To this end, this question is basically about dealing with monoids (see related questions below for more about this) and the library in question is called scalaz.
Using scalaz FP, this is just:
def add(a: Option[Int], b: Option[Int]) = ~(a |+| b)
What is more this works on any monoid M:
def add[M: Monoid](a: Option[M], b: Option[M]) = ~(a |+| b)
Even more usefully, it works on any number of them placed inside a Foldable container:
def add[M: Monoid, F: Foldable](as: F[Option[M]]) = ~as.asMA.sum
Note that some rather useful monoids, aside from the obvious Int, String, Boolean are:
Map[A, B: Monoid]A => (B: Monoid)Option[A: Monoid]In fact, it's barely worth the bother of extracting your own method:
scala> some(some(some(1))) #:: some(some(some(2))) #:: Stream.empty
res0: scala.collection.immutable.Stream[Option[Option[Option[Int]]]] = Stream(Some(Some(Some(1))), ?)
scala> ~res0.asMA.sum
res1: Option[Option[Int]] = Some(Some(3))
Q. What is a monoid?
A monoid is a type
Mfor which there exists an associative binary operation(M, M) => Mand an identityIunder this operation, such thatmplus(m, I) == m == mplus(I, m)for allmof typeM
Q. What is |+|?
This is just scalaz shorthand (or ASCII madness, ymmv) for the
mplusbinary operation
Q. What is ~?
It is a unary operator meaning "or identity" which is retrofitted (using scala's implicit conversions) by the scalaz library onto
Option[M]ifMis a monoid. Obviously a non-empty option returns its contents; an empty option is replaced by the monoid's identity.
Q. What is asMA.sum?
A
Foldableis basically a datastructure which can be folded over (likefoldLeft, for example). Recall thatfoldLefttakes a seed value and an operation to compose successive computations. In the case of summing a monoid, the seed value is the identityIand the operation ismplus. You can hence callasMA.sumon aFoldable[M : Monoid]. You might need to useasMAbecause of the name clash with the standard library'ssummethod.
def addOpt(ao: Option[Int], bo: Option[Int]) =
for {
a <- ao
b <- bo
} yield a + b
(Repeating comment above in an answer as requested)
You don't extract the content of the option the proper way. When you match with case Some(x), x is the value inside the option(type Int) and you don't call get on that. Just do
case Some(x) => x
Anyway, if you want content or default, a.getOrElse(0) is more convenient
If they both default to 0 you don't need pattern matching:
def addOpt(a:Option[Int], b:Option[Int]) = {
a.getOrElse(0) + b.getOrElse(0)
}
def addOpts(xs: Option[Int]*) = xs.flatten.sum
This will work for any number of inputs.