对于Scala,如何在第一个错误时停止,但获取已计算的值
例如,假设我有一个函数对于Scala,如何在第一个错误时停止,但获取已计算的值,scala,functional-programming,Scala,Functional Programming,例如,假设我有一个函数 def foo(): Either[String, Int] = ??? 我想调用这个函数三次。如果所有值都正确,则我需要求和。如果我有一个左,我想得到错误和所有先前右值的总和(~此时停止计算) 我找到的唯一方法是: List(foo, foo, foo).foldLeft((None, 0)) { case ((Some(err), sum), _) => (Some(err), sum) case ((None, sum), fn) => f
def foo(): Either[String, Int] = ???
我想调用这个函数三次。如果所有值都正确
,则我需要求和。如果我有一个左
,我想得到错误和所有先前右
值的总和(~此时停止计算)
我找到的唯一方法是:
List(foo, foo, foo).foldLeft((None, 0)) {
case ((Some(err), sum), _) => (Some(err), sum)
case ((None, sum), fn) => fn() match {
case Left(err) => (Some(err), sum)
case Right(x) => (None, sum + x)
}
}
是否有一些通用的函数式编程特性(例如cats或scalaz)可以做到这一点 与尾部递归函数的解决方案基本相同:
def sumRights(allFoos: List[() => Either[String, Int]], accum: Int = 0): (Option[String], Int) = {
allFoos match {
case Nil => (None, accum)
case head :: tail =>
head() match {
case Right(x) => sumRights(tail, accum + x)
case Left(err) => (Some(err), accum)
}
}
另一个必要的解决方案是在第一个左边用
splitWhere
进行拆分,并将第一个输出列表的所有值相加。我不确定猫的scalaz是否有专门用于此的内容,但下面是如何在vanilla scala中解决此问题:
Stream.continually(foo()).take(3) match {
case s =>
val err = s.collectFirst {
case Left(err) => err
}
val sum = s.takeWhile(_.isRight)
.flatMap(_.right.toOption)
.sum
(err, sum)
}
流
将被延迟计算并缓存
def rec(sum: Int = 0, i: Int = 2): (Option[String], Int) =
if (i < 0) (None, sum) else foo() match {
case Left(e) => (Some(e), sum)
case Right(s) => rec(s + sum, i - 1)
}
def rec(sum:Int=0,i:Int=2):(选项[String],Int)=
如果(i<0)(无,求和)else foo()匹配{
案例左(e)=>(部分(e),总和)
案例右侧=>rec(s+sum,i-1)
}
使用
Stream.span
:
val (ints, rest) = Stream.continually(foo()).take(3).span(_.isRight)
val sum = ints.map(_.right.get).sum
val error = rest.headOption
您的尾部递归不满足对
foo
:“~在这一点上停止计算”的延迟求值要求。确实!重写为接受函数列表而不是值列表。