Scala函数式编程体操

标签 scala functional-programming scalaz

我正在尝试以尽可能少的代码和尽可能在功能上执行以下操作:

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/

相关文章:

Java 编译速度 vs Scala 编译速度

scala - Spark-读取许多小的 Parquet 文件之前需要获取每个文件的状态

list - 以所有可能性在 Haskell 中旋转列表

swift - 如何在数组的每两个元素之间重复插入一个项目?

scala - 使用 scala Maps 来累加值

scala - 如何在 Scala 中重命名文件?

scala - 在 Scala 中覆盖 val

python - 在 python 或 coffeescript 中,为什么 list.append 不返回列表本身?如果是这样,递归可以简单得多

validation - 如何在Scala中实现简单的验证

scala - Kleisli Arrow with Writer in Scala。为什么不编译?