我现在有点累了所以我可能会错过这个显而易见的事情。
我有一个var _minVal: Option[Double]
,它应该包含Double
s集合中包含的最小值(如果集合为空,则为None)
在向集合中添加新项目时,我也检查_minVal
是否为None或大于新项目(=新mimimum候选项)。
我已离开
_minVal = Some(_minVal match {
case Some(oldMin) => if (candidate < oldMin) candidate
else oldMin
case None => candidate
})
(不是很干)
_minVal = Some(min(_minVal getOrElse candidate, candidate))
但仍然认为我可能会遗漏某些东西......
答案 0 :(得分:10)
如果没有Scalaz,你将支付一些RY。但我会把它写成:
_minVal = _minVal map (candidate min) orElse Some(candidate)
修改强>
Eric Torreborre / Specs成名的{p> Specs2非常友好,可以追求我未能找到的Scalaz解决方案。作为一个测试框架的人,他以测试格式编写答案,而不是命令性的副作用原文。 : - )以下是使用_minVal
,Double
而不是Int
的版本,副作用以及我的一些曲折现在,Eric已经做了很多努力。
// 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)
答案 1 :(得分:7)
以下是使用Scalaz对Daniel的回答的更新:
这是一个咖喱'min'功能:
def min = (i: Int) => (j: Int) => if (i < j) i else j
和2个变量:
// the last minimum value
def lastMin: Option[Int] = None
// the new value
def current = 1
现在让我们定义2个新函数
// 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)
然后使用why Function1[T, _] is an applicative functor的@dibblego的优秀解释,我们可以避免重复“当前”变量:
(updateMin <*> orElse).apply(current) === Some(current)