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)