功能组合,累积中间结果

时间:2015-08-31 14:41:38

标签: scala function composition

假设我有一些函数Int => Option[Int]

val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None

现在我想把它们组成创建一个新函数,它累积中间结果,即f1f2和{{1}的结果}。

所以我添加了一个新课程f3

Accumulator

现在我可以看到计算的所有中间结果:

class Accumulator(x: Int) {
  val ox1 = f1(x)
  val ox2 = ox1.flatMap(f2)
  val ox3 = ox2.flatMap(f3)
  def apply() = ox3
}

val f = {x => new Accumulator(x)}

我不喜欢这种方法,因为每次计算需要一个新类。您能否建议另一种方法来编写由scala> f(0) res18: X = $$$a5cddfc4633c5dd8aa603ddc4f9aad5$$$$w$X@10596df6 scala> res18.ox1 res19: Option[Int] = Some(1) scala> res18.ox2 res20: Option[Int] = Some(3) scala> res18() res21: Option[Int] = Some(6) ff1组成的函数f2,该函数也返回中间结果,即f3的结果,f1f2来电。

2 个答案:

答案 0 :(得分:5)

为什么不将foldLeft与函数列表一起使用?

def accumulate(x: Int, funcs: List[Int => Option[Int]]): List[Option[Int]] = funcs.foldLeft(List[Option[Int]]()) {
  case (Nil, func) => List(func(x))
  case (res :: tail, func) => res.flatMap(func) :: res :: tail
}.reverse

val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None

accumulate(0, List(f1, f2, f3))

这会给List[Option[Int]] = List(Some(1), Some(3), Some(6))

修改

正如Marth指出的那样,有一个专门的功能 - scanLeft,但是,我想提出一种不同的方法来使用它。将初始值设为输入参数而不是函数:

def accumulate(x: Int, funcs: List[Int => Option[Int]]): List[Option[Int]] =
  funcs.scanLeft(Option(x)) {
    case (acc, op) => acc.flatMap(op)
  }.tail

val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None

accumulate(0, List(f1, f2, f3))

答案 1 :(得分:5)

您可以.scanLeft使用List Function,(来自文档):

  

生成包含应用累积结果的集合   操作员从左到右。

scala> val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
f1: Int => Option[Int] = <function1>

scala> val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
f2: Int => Option[Int] = <function1>

scala> val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None
f3: Int => Option[Int] = <function1>

scala> val fList = List(f1,f2,f3)
fList: List[Int => Option[Int]] = List(<function1>, <function1>, <function1>)

scala> val composed = fList.scanLeft((x:Int) => Option(x)) {
         case (composedFun, f) => (x:Int) => (composedFun(x)) flatMap f 
       }.tail
composedFunctions: List[Int => Option[Int]] = List(<function1>, <function1>, <function1>)

scala> composed.map(_(2))
res24: List[Option[Int]] = List(Some(3), Some(5), Some(8))

scala> composed.map(_(8))
res25: List[Option[Int]] = List(Some(9), Some(11), None)

请注意,我必须引入一个初始值(z,这里是(x:Int) => Option(x))  您可能希望编写一个函数,该函数采用函数列表并使用funList.head作为初始值(并在.scanLeft而不是funList.tail上调用funList)。