I am trying to do the following in as little code as possible and as functionally as possible:
def restrict(floor : Option[Double], cap : Option[Double], amt : Double) : Double
Obviously the following works:
= (floor -> cap) match {
case (None, None) => amt
case (Some(f), None) => f max amt
case (None, Some(c)) => c min amt
case (Some(f), Some(c)) => (f max amt) min c
}
I was really hoping for something more elegant and will accept use of the Scalaz library! You can assume that the following is true:
floor.forall( f => cap.forall( _ > f))
If anyone is interested, here is some test code:
object Comparisons {
sealed trait Cf {
def restrict(floor: Option[Double], cap: Option[Double], amt: Double): Double
}
def main(args: Array[String]) {
val cf : Cf = //TODO - your impl here!
def runtest(floor: Option[Double], cap: Option[Double], amt: Double, exp : Double) : Unit = {
val ans = cf.restrict(floor, cap, amt)
println("floor=%s, cap=%s, amt=%s === %s (%s) : %s".format(floor, cap, amt, ans, exp, if (ans == exp) "PASSED" else "FAILED"))
}
runtest(Some(3), Some(5), 2, 3)
runtest(Some(3), Some(5), 3, 3)
runtest(Some(3), Some(5), 4, 4)
runtest(Some(3), Some(5), 5, 5)
runtest(Some(3), Some(5), 6, 5)
runtest(Some(3), None, 2, 3)
runtest(Some(3), None, 3, 3)
runtest(Some(3), None, 4, 4)
runtest(Some(3), None, 5, 5)
runtest(Some(3), None, 6, 6)
runtest(None, Some(5), 2, 2)
runtest(None, Some(5), 3, 3)
runtest(None, Some(5), 4, 4)
runtest(None, Some(5), 5, 5)
runtest(None, Some(5), 6, 5)
runtest(None, None, 2, 2)
runtest(None, None, 3, 3)
runtest(None, None, 4, 4)
runtest(None, None, 5, 5)
runtest(None, None, 6, 6)
}
}
Edit 2:
While thinking about the
cataXmethod, I figured out thatcataXis nothing else than a plain and simple fold. Using that, we can get a pure scala solution without any additional libraries.So, here it is:
which is the same as
(not that this is necessarily easier to understand).
I think you can’t have it any shorter than that.
For better or worse, we can also solve it using scalaz:
or even:
As a ‘normal’ Scala programmer, one might not know about the special Scalaz operators and methods used (
|>andOption.cata). They work as follows:value |> functiontranslates tofunction(value)and thusamt |> (m => v fun m)is equal tov fun amt.opt.cata(fun, v)translates toor
opt.map(fun).getOrElse(v).See the Scalaz definitions for
cataand|>.A more symmetric solution would be:
Edit: Sorry, it’s getting weird now, but I wanted to have a point-free version as well. The new
cataXis curried. The first parameter takes a binary function; the second is a value.If
omatchesSomewe return the function with the value ofoand the second parameter applied, ifomatchesNonewe only return the second parameter.And here we go:
Maybe they already have this in Scalaz…?