Question

I have a pair of Option[Int] and want to find the minimum of the two values, if they both exist, otherwise just one of them. Let's say I have a function minOption:

def minOption(a: Option[Int], b: Option[Int]): Option[Int]

What I want is the following mapping of input to output:

(Some(a), Some(b)) => Some(Math.min(a,b))
(Some(a), None) => Some(a)
(None, Some(b)) => Some(b)
(None, None) => None

Is there an easy way to do this? I couldn't come up with a different than the obvious way using nested pattern match.

I would assume that this should be trivial to do in scalaz, but I am not very familiar with it yet and couldn't find a way.

Was it helpful?

Solution

There is a semigroup for things tagged with Tags.MinVal which selects the minimum val:

scala> import scalaz._ ; import Scalaz._ ; import Tags._
import scalaz._
import Scalaz._
import Tags._

scala> MinVal(3).some |+| MinVal(1).some
res0: Option[scalaz.@@[Int,scalaz.Tags.MinVal]] = Some(1)

scala> MinVal(3).some |+| none[Int @@ MinVal]
res1: Option[scalaz.@@[Int,scalaz.Tags.MinVal]] = Some(3)

scala> none[Int @@ MinVal] |+| none[Int @@ MinVal]
res2: Option[scalaz.@@[Int,scalaz.Tags.MinVal]] = None

In the above, Int @@ MinVal is a type which is a subtype of Int, which has been "Tagged" with MinVal, which helps select the right semigroup. MinVal(x: Int) returns x with the type Int @@ MinVal. x.some is like Some(x) except the type is Option instead of Some, and this helps with type inference (there is a Semigroup for Option, but not for Some), similarly none[T] returns None, but its type is Option[T] instead of None (helpful for the same reasons, there is no Semigroup for None, but there is one for Option)

If there are more than two, perhaps you have a list of these, you can use suml:

scala> List(MinVal(2).some, None, MinVal(3).some, None, MinVal(1).some).suml
res5: Option[scalaz.@@[Int,scalaz.Tags.MinVal]] = Some(1)

OTHER TIPS

I don't think you need Scalaz for that one: assuming your options are contained in a list (works using varargs as well)

 def findMinOpt(li: List[Option[Int]]): Option[Int] =
    {
      val listwithoutOptions = li.flatten
      listwithoutOptions.reduceLeftOption(_ min _)
    }


 def findMinOptVarArgs(li: Option[Int]*): Option[Int] =
    {
      val listwithoutOptions = li.flatten
      listwithoutOptions.reduceLeftOption(_ min _)
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top