Scala 函数组合,它积累中间结果

Scala 函数组合,它积累中间结果,scala,function,composition,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) els

假设我有几个函数
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
现在我可以看到计算的所有中间结果:

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)

我不喜欢这种方法,因为每次计算都需要一个新类。您是否可以建议另一种方法来编写一个函数
f
,它由
f1
f2
f3
组成,同时返回中间结果,即
f1
f2
f3
调用的结果。

为什么不将
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))

您可以在
函数
列表
上使用
.scanlight
,该列表(来自文档):

生成一个集合,其中包含应用 接线员从左向右

scala>valf1:Int=>Option[Int]=x=>if(x<10)Some(x+1)else无
f1:Int=>选项[Int]=
scala>valf2:Int=>Option[Int]=x=>if(x<10)部分(x+2)其他无
f2:Int=>选项[Int]=
scala>valf3:Int=>Option[Int]=x=>if(x<10)Some(x+3)else无
f3:Int=>选项[Int]=
scala>val fList=List(f1、f2、f3)
fList:List[Int=>Option[Int]]=List(,)
scala>valcomposited=fList.scanlight((x:Int)=>Option(x)){
case(composedFun,f)=>(x:Int)=>(composedFun(x))平面图f
}.尾巴
composedFunctions:List[Int=>Option[Int]]=List(,)
scala>composited.map(2))
res24:List[Option[Int]]=List(一些(3),一些(5),一些(8))
scala>composited.map(8))
res25:List[Option[Int]]=List(一些(9),一些(11),无)

注意,我必须引入一个初始值(z,这里是
(x:Int)=>选项(x)
)。

您可能希望编写一个函数,该函数采用函数列表并使用
funList.head
作为初始值(并在
funList.tail
上调用
.scanlight
,而不是
funList
)。

您还应该编辑结果谢谢。现在我想知道如何为函数
A=>Option[B]
B=>Option[C]
C=>Option[D]
,等等实现这一点。@Michael我想你最好把函数列表键入
list[Any=>Option[Any]
答案很好。我还要补充一点,因为这些函数是kleisli箭头,所以我们可以使用Scalaz以更具语义的方式组合它们:
kleisli(composedFun)>=>kleisli(f)
而不是
(x:Int)=>(composedFun(x))flatMap f
。或者更好的是,
列表(f1,f2,f3)。map(kleisli(\u))
然后简单地
composedFun>=>f
@Michael请查看我的编辑,使用
scanleet
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))
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))
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)