I’m currently a little tired so I might be missing the obvious.
I have a var _minVal: Option[Double]
, which shall hold the minimal value contained in a collection of Double
s (or None, if the collection is empty)
When adding a new item to the collection, I have too check if _minVal
is either None or greater than the new item (=candidate for new mimimum).
I’ve gone from
_minVal = Some(_minVal match {
case Some(oldMin) => if (candidate < oldMin) candidate
else oldMin
case None => candidate
})
(not very DRY) to
_minVal = Some(min(_minVal getOrElse candidate, candidate))
but still think I might be missing something…
Without Scalaz, you are going to pay some RY. But I'd write it as:
_minVal = _minVal map (candidate min) orElse Some(candidate)
EDIT
Eric Torreborre, of Specs/Specs2 fame, was kind enough to pursue the Scalaz solution that has eluded me. Being a testing framework guy, he wrote the answer in a testing format, instead of the imperative, side-effecting original. :-)
Here's the version using _minVal
, Double
instead of Int
, side-effects, and some twists of mine now that Eric has done the hard work.
// From the question (candidate provided for testing purposes)
var _minVal: Option[Double] = None
def candidate = scala.util.Random.nextDouble
// A function "min"
def min = (_: Double) min (_: Double)
// A function "orElse"
def orElse = (_: Option[Double]) orElse (_: Option[Double])
// Extract function to decrease noise
def updateMin = _minVal map min.curried(_: Double)
// This is the Scalaz vesion for the above -- type inference is not kind to it
// def updateMin = (_minVal map min.curried).sequence[({type lambda[a] = (Double => a)})#lambda, Double]
// Say the magic words
import scalaz._
import Scalaz._
def orElseSome = (Option(_: Double)) andThen orElse.flip.curried
def updateMinOrSome = updateMin <*> orElseSome
// TAH-DAH!
_minVal = updateMinOrSome(candidate)
Here is an update to Daniel's answer, using Scalaz:
Here's a curried 'min' function:
def min = (i: Int) => (j: Int) => if (i < j) i else j
And 2 variables:
// the last minimum value
def lastMin: Option[Int] = None
// the new value
def current = 1
Now let's define 2 new functions
// this one does the minimum update
def updateMin = (i: Int) => lastMin map (min(i))
// this one provides a default value if the option o2 is not defined
def orElse = (o1: Int) => (o2: Option[Int]) => o2 orElse Some(o1)
Then using the excellent explanation by @dibblego of why Function1[T, _] is an applicative functor, we can avoid the repetition of the 'current' variable:
(updateMin <*> orElse).apply(current) === Some(current)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With