Correct way to work with two instances of Option together - scala

When I have one Option[T] instance it is quite easy to perform any operation on T using monadic operations such as map() and flatMap(). This way I don't have to do checks to see whether it is defined or empty, and chain operations together to ultimately get an Option[R] for the result R.
My difficulty is whether there is a similar elegant way to perform functions on two Option[T] instances.
Lets take a simple example where I have two vals, x and y of type Option[Int]. And I want to get the maximum of them if they are both defined, or the one that is defined if only one is defined, and None if none are defined.
How would one write this elegantly without involving lots of isDefined checks inside the map() of the first Option?

You can use something like this:
def optMax(op1:Option[Int], op2: Option[Int]) = op1 ++ op2 match {
case Nil => None
case list => list.max
}
Or one much better:
def f(vars: Option[Int]*) = (for( vs <- vars) yield vs).max
#jwvh,thanks for a good improvement:
def f(vars: Option[Int]*) = vars.max

Usually, you'll want to do something if both values are defined.
In that case, you could use a for-comprehension:
val aOpt: Option[Int] = getIntOpt
val bOpt: Option[Int] = getIntOpt
val maxOpt: Option[Int] =
for {
a <- aOpt
b <- bOpt
} yield max(a, b)
Now, the problem you described is not as common. You want to do something if both values are defined, but you also want to retrieve the value of an option if only one of them is defined.
I would just use the for-comprehension above, and then chain two calls to orElse to provide alternative values if maxOpt turns out to be None.
maxOpt orElse aOpt orElse bOpt
orElse's signature:
def orElse[B >: A](alternative: ⇒ Option[B]): Option[B]

Here's another fwiw:
import scala.util.Try
def maxOpt (a:Option[Int]*)= Try(a.flatten.max).toOption
It works with n arguments (including zero arguments).

Pattern matching would allow something easy to grasp, but that might not be the most elegant way:
def maxOpt[T](optA: Option[T], optB: Option[T])(implicit f: (T, T) => T): Option[T] = (optA, optB) match {
case (Some(a), Some(b)) => Some(f(a, b))
case (None, Some(b)) => Some(b)
case (Some(a), None) => Some(a)
case (None, None) => None
}
You end up with something like:
scala> maxOpt(Some(1), None)(Math.max)
res2: Option[Int] = Some(1)
Once you have that building, block, you can use it inside for-comp or monadic operations.

To get maxOpt, you can also use an applicative, which using Scalaz would look like (aOpt |#| bOpt) { max(_, _) } & then chain orElses as #dcastro suggested.

I assume you expect Some[Int]|None as a result, not Int|None (otherwise return type has to be Any):
def maxOption(opts: Option[Int]*) = {
val flattened = opts.flatten
flattened.headOption.map { _ => flattened.max }
}

Actually, Scala already gives you this ability more or less directly.
scala> import Ordering.Implicits._
import Ordering.Implicits._
scala> val (a,b,n:Option[Int]) = (Option(4), Option(9), None)
a: Option[Int] = Some(4)
b: Option[Int] = Some(9)
n: Option[Int] = None
scala> a max b
res60: Option[Int] = Some(9)
scala> a max n
res61: Option[Int] = Some(4)
scala> n max b
res62: Option[Int] = Some(9)
scala> n max n
res63: Option[Int] = None

A Haskell-ish take on this question is to observe that the following operations:
max, min :: Ord a => a -> a -> a
max a b = if a < b then b else a
min a b = if a < b then a else b
...are associative:
max a (max b c) == max (max a b) c
min a (min b c) == min (min a b) c
As such, any type Ord a => a together with either of these operations is a semigroup, a concept for which reusable abstractions can be built.
And you're dealing with Maybe (Haskell for "option"), which adds a generic "neutral" element to the base a type (you want max Nothing x == x to hold as a law). This takes you into monoids, which are a subtype of semigroups.
The Haskell semigroups library provides a Semigroup type class and two wrapper types, Max and Min, that generically implement the corresponding behaviors.
Since we're dealing with Maybe, in terms of that library the type that captures the semantics you want is Option (Max a)—a monoid that has the same binary operation as the Max semigroup, and uses Nothing as the identity element. So then the function simply becomes:
maxOpt :: Ord a => Option (Max a) -> Option (Max a) -> Option (Max a)
maxOpt a b = a <> b
...which since it's just the <> operator for Option (Max a) is not worth writing. You also gain all the other utility functions and classes that work on Semigroup and Monoid, so for example to find the maximum element of a [Option (Max a)] you'd just use the mconcat function.
The scalaz library comes with a Semigroup and a Monoid trait, as well as Max, Min, MaxVal and MinVal tags that implement those traits, so in fact the stuff that I've demonstrated here in Haskell exists in scalaz as well.

Related

Fold method using List as accumulator

To find prime factors of a number I was using this piece of code :
def primeFactors(num: Long): List[Long] = {
val exists = (2L to math.sqrt(num).toLong).find(num % _ == 0)
exists match {
case Some(d) => d :: primeFactors(num/d)
case None => List(num)
}
}
but this I found a cool and more functional approach to solve this using this code:
def factors(n: Long): List[Long] = (2 to math.sqrt(n).toInt)
.find(n % _ == 0).fold(List(n)) ( i => i.toLong :: factors(n / i))
Earlier I was using foldLeft or fold simply to get sum of a list or other simple calculations, but here I can't seem to understand how fold is working and how this is breaking out of the recursive function.Can somebody plz explain how fold functionality is working here.
Option's fold
If you look at the signature of Option's fold function, it takes two parameters:
def fold[B](ifEmpty: => B)(f: A => B): B
What it does is, it applies f on the value of Option if it is not empty. If Option is empty, it simply returns output of ifEmpty (this is termination condition for recursion).
So in your case, i => i.toLong :: factors(n / i) represents f which will be evaluated if Option is not empty. While List(n) is termination condition.
fold used for collection / iterators
The other fold that you are taking about for getting sum of collection, comes from TraversableOnce and it has signature like:
def foldLeft[B](z: B)(op: (B, A) => B): B
Here, z is starting value (suppose incase of sum it's 0) and op is associative binary operator which is applied on z and each value of collection from left to right.
So both folds differ in their implementation.

Scala: How do I calculate the variance of a Seq[Double] using flatMap and Options?

I am trying to solve a "simple" exercise in Scala. I have this function:
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)
This is the text of the exercise:
EXERCISE 2: Implement the variance function (if the mean is m ,
variance is the mean of math.pow(x - m, 2) , see definition ) in terms
of mean and flatMap .
I was thinking something like
val xs = List(1.3,2.1,3.2)
val m = mean(xs)
xs flatMap(x=> math.pow(x-m,2)).mean //error!
What is the right way to solve? If possible I would like also a small theoretical explanation
I wouldn't call this simple.
map on Option[A] takes a function A => B and returns an Option[B] which is a Some if the original was a Some, and None otherwise. So Some(2).map(_+2) gives Some(4), but None[Int].map(_+2) gives None.
flatMap is much the same, but it takes a function A => Option[B] and still returns an Option[B]. If the original is None or the given function results in None, the result is None otherwise it's a Some[B].
You don't want to flatMap over the list, you want to flatMap the option. I'll give you a hint, it starts with:
mean(xs).flatMap(m => ...
After that arrow, m is a Double, not an Option[Double].
Edit:
Alright, fine, since we're getting all downvotey and not being helpful, here's the full answer:
def variance(xs: Seq[Double]): Option[Double] = {
mean(xs).flatMap(m => mean(xs.map(x => Math.pow(x-m, 2))))
}
Matt Putnam's answer gives some good pointers. I found it easier to understand this problem by breaking it up into smaller chunks.
scala> val xs = List(1.3,2.1,3.2)
xs: List[Double] = List(1.3, 2.1, 3.2)
scala> def mean(xs: Seq[Double]): Option[Double] = {
| if (xs.isEmpty) None
| else Some(xs.sum / xs.length)
| }
mean: (xs: Seq[Double])Option[Double]
Calculate the deviation of each element from the mean of the sequence:
scala> mean(xs).map(m => xs.map(x => x-m))
res0: Option[List[Double]] = Some(List(-0.9000000000000001, -0.10000000000000009, 1.0))
map works because if mean(xs) is Some, x => x-m is evaluated. Otherwise it isn't and we get None.
Now calculate the squared deviation from the mean of the sequence:
scala> mean(xs).map(m => xs.map(x => math.pow(x-m, 2)))
res1: Option[List[Double]] = Some(List(0.8100000000000003, 0.010000000000000018, 1.0))
Then calculate the mean of that:
scala> mean(xs).map(m => mean(xs.map(x => math.pow(x-m, 2))))
res2: Option[Option[Double]] = Some(Some(0.6066666666666668))
But here we have an Option that contains an Option, so we use flatMap to get the value of the first Some. So the solution with the desired return type Option[Double] is:
scala> mean(xs).flatMap(m => mean(xs.map(x => math.pow(x-m, 2))))
res3: Option[Double] = Some(0.6066666666666668)

Pattern for chaining together calls that take in Options

I'm finding that I often have to chain together functions that work on an Option and return a different Option that look something like this:
if(foo.isDefined) someFunctionReturningOption(foo.get) else None
Is there a cleaner way to do this? This pattern gets quite verbose with more complicated variables.
I'm seeing it a fair bit in form handling code that has to deal with optional data. It'll insert None if the value is None or some transformation (which could potentially fail) if there is some value.
This is very much like the ?. operator proposed for C#.
You can use flatMap:
foo.flatMap(someFunctionReturningOption(_))
Or in a for-comprehension:
for {
f <- foo
r <- someFunctionReturningOption(f)
} yield r
The for-comprehension is preferred when chaining multiple instances of these functions together, as they de-sugar to flatMaps.
There're a lot of options (pun intended) but for comprehensions, I guess, is the most convinient in case of chains
for {
x <- xOpt
y <- someFunctionReturningOption(x)
z <- anotherFunctionReturningOption(y)
} yield z
You're looking for flatMap:
foo.flatMap(someFunctionReturningOption)
This fits into the general monadic structure, where a monad wrapping a type uses flatMap to return the same type (e.g. flatMap on Seq[T] returns a Seq).
Option supports map() so when x is an Option[Int] this construct:
if (x.isDefined)
"number %d".format(x.get)
else
None
is easier to write as:
x map (i => "number %d".format(i))
map will keep None unmodified, but it will apply the function you pass to it to any value, and wrap the result back into an Option. For example note how 'x' gets converted to a string message below, but 'y' gets passed along as None:
scala> val x: Option[Int] = Some(3)
x: Option[Int] = Some(3)
scala> val y: Option[Int] = None
y: Option[Int] = None
scala> x map (i => "number %d".format(i))
res0: Option[String] = Some(number 3)
scala> y map (i => "number %d".format(i))
res1: Option[String] = None

Composing Options in an idiomatic way

I'm going to write this in Scala, but it's more of a functional programming question.
I have
def foo(x: A): Option[B]
and
def bar(x:B, y:B): C
What's the neatest way to do the following:
def compose(x:A, y:A): Option[C]
such that if either foo(x) of foo(y) are None, then compose(x,y) is None, otherwise compose(x,y) is bar(foo(x).get, foo(y).get). The best I could come up with is:
foo(a).flatMap( aRes => foo(b).map( bRes => bar(a,b)))
The following is syntactic sugar for your current solution:
def compose(x: A, y: A): Option[C] = for {
fx <- foo(x)
fy <- foo(y)
} yield bar(fx, fy)
Sometimes this approach is nicer than writing out flatMap and map, and sometimes it's not. You'll probably find that you pretty quickly develop strong preferences about this kind of thing. Either could be considered idiomatic Scala.
Since you've indicated that you're interested in the question more generally from the perspective of functional programming, however, it's worth noting that the solutions above are overkill in a sense. They take advantage of the fact that Option is monadic, but for this operation you don't actually need all of that power—the fact that Option has an applicative functor instance is enough. To summarize very informally, flatMap gives you sequencing that you don't need here, since the computation of fy doesn't depend on the computation of fx. Using the applicative functor for Option allows you to more clearly capture the fact that there's no dependency between the two computations.
The Scala standard library doesn't provide any kind of representation of applicative functors, but Scalaz does, and with Scalaz you could write your method like this (see the "appendix" of my answer here for some discussion of the syntax):
import scalaz._, Scalaz._
def compose(x: A, y: A): Option[C] = (foo(x) |#| foo(y))(bar)
This will produce the same result as the implementation above, but using a more appropriate abstraction.
How about:
for (x <- foo(a); y <- foo(b)) yield bar(x,y)
for instance:
type A = Int
type C = (A,A)
def foo(x: A): Option[A] = if (x > 0) Some(x) else None
def bar(x: A, y: A): C = x -> y
for (x <- foo(1); y <- foo(2)) yield bar(x,y)
// Option[C] = Some((1,2))
for (x <- foo(-1); y <- foo(2)) yield bar(x,y)
// Option[C] = None
Depending on your taste the very first could be written as:
for {
x <- foo(a)
y <- foo(b)
} yield bar(x,y)

Binary operator with Option arguments

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 doubles but this example is simpler).
I tried the following but it 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 actual problem, I'm adding two maps which are standins for sparse vectors. So the None case returns Map[Int, Double] and the + is actually a ++ (with the tweak at stackoverflow.com/a/7080321/614684)
Monoids
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))
Some related questions
Q. What is a monoid?
A monoid is a type M for which there exists an associative binary operation (M, M) => M and an identity I under this operation, such that mplus(m, I) == m == mplus(I, m) for all m of type M
Q. What is |+|?
This is just scalaz shorthand (or ASCII madness, ymmv) for the mplus binary 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] if M is 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 Foldable is basically a datastructure which can be folded over (like foldLeft, for example). Recall that foldLeft takes a seed value and an operation to compose successive computations. In the case of summing a monoid, the seed value is the identity I and the operation is mplus. You can hence call asMA.sum on a Foldable[M : Monoid]. You might need to use asMA because of the name clash with the standard library's sum method.
Some References
Slides and Video of a talk I gave which gives practical examples of using monoids in the wild
def addOpts(xs: Option[Int]*) = xs.flatten.sum
This will work for any number of inputs.
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)
}
(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
def addOpt(ao: Option[Int], bo: Option[Int]) =
for {
a <- ao
b <- bo
} yield a + b