我正在尝试以尽可能少的代码和尽可能在功能上执行以下操作:
def restrict(floor : Option[Double], cap : Option[Double], amt : Double) : Double
显然,以下工作:
= (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
}
我真的希望有更优雅的东西,并且会接受使用 Scalaz 图书馆!您可以假设以下情况为真:
floor.forall( f => cap.forall( _ > f))
如果有人感兴趣,这里是一些测试代码 :
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)
}
}
最佳答案
编辑 2 :
一边想着cataX
方法,我发现cataX
无非是简单的折叠。使用它,我们可以获得一个纯 Scala 解决方案,而无需任何额外的库。
所以,这里是:
( (amt /: floor)(_ max _) /: cap)(_ min _)
这与
cap.foldLeft( floor.foldLeft(amt)(_ max _) )(_ min _)
(并不是说这一定更容易理解)。
我认为你不能拥有比这更短的时间。
无论好坏,我们也可以使用 scalaz 解决它:
floor.map(amt max).getOrElse(amt) |> (m => cap.map(m min).getOrElse(m))
甚至:
floor.cata(amt max, amt) |> (m => cap.cata(m min, m))
作为一名“普通”Scala 程序员,您可能不知道所使用的特殊 Scalaz 运算符和方法(
|>
和 Option.cata
)。它们的工作方式如下:value |> function
转换为 function(value)
因此 amt |> (m => v fun m)
等于 v fun amt
.opt.cata(fun, v)
翻译成opt match {
case Some(value) => fun(value)
case None => v
}
或
opt.map(fun).getOrElse(v)
.参见
cata
的 Scalaz 定义和 |>
.更对称的解决方案是:
amt |> (m => floor.cata(m max, m)) |> (m => cap.cata(m min, m))
编辑:抱歉,现在变得很奇怪,但我也想要一个免积分版本。新款
cataX
是 curry 。第一个参数采用二元函数;第二个是值(value)。class CataOption[T](o: Option[T]) {
def cataX(fun: ((T, T) => T))(v: T) = o.cata(m => fun(m, v), v)
}
implicit def option2CataOption[T](o: Option[T]) = new CataOption[T](o)
如
o
匹配 Some
我们返回值为 o
的函数并且应用第二个参数,如果 o
匹配 None
我们只返回第二个参数。现在我们开始:
amt |> floor.cataX(_ max _) |> cap.cataX(_ min _)
也许他们已经在 Scalaz 有了这个……?
关于Scala函数式编程体操,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4145196/