Binary operator with Option arguments

In scala, how can I define an addition with two Option arguments? Let's say they are wrappers for Int types (I actually work with double maps, but this example is simpler).

I tried the following, but this just gives me an error:

  def addOpt(a:Option[Int], b:Option[Int]) = { a match { case Some(x) => x.get case None => 0 } + b match { case Some(y) => y.get case None => 0 } } 

Edited to add:

In my real problem, I add two cards that are standins for sparse vectors. So the None case returns Map [Int, Double], and + is actually ++ (with the setting on stackoverflow.com/a/7080321/614684)

+6
source share
5 answers

(Repeating the comment above in the response on request)

You are not extracting the contents of the option properly. When you match case Some(x) , x is the value inside the option (type Int ), and you don't call get . Just do

 case Some(x) => x 

In any case, if you need content or a default value, a.getOrElse(0) more convenient

+4
source

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(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)) 

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.
+25
source
 def addOpts(xs: Option[Int]*) = xs.flatten.sum 

This will work for any number of inputs.

+10
source

If both default values ​​are 0, you do not need pattern matching:

  def addOpt(a:Option[Int], b:Option[Int]) = { a.getOrElse(0) + b.getOrElse(0) } 
+5
source
 def addOpt(ao: Option[Int], bo: Option[Int]) = for { a <- ao b <- bo } yield a + b 
0
source

Source: https://habr.com/ru/post/915904/


All Articles