我在一个内部,我们将多个操作组合在一起。每个步骤完成后,我需要使用MonadError.raiseError
抛出错误,或者如果有效的话继续进行下一步。
def myFunc[F[_]: Monad](input: Input)(implicit err: MonadError) = {
for {
stepAResult <- runStepA(input)
if (stepAResult.isInstanceOf[Invalid[_]) {
err.raiseError(new Throwable("error 1"))
} else {
stepBResult<- runStepB(stepAResult.toOption.get, input)
if (stepBResult.isInstanceOf[Invalid[_]]) {
err.raiseError(new Throwable("error 2"))
} else {
stepCResult <- runStepC(stepBResult.toOption.get)
// check for invalid here again.
}
}
}
}
这不能编译。我需要了解是否有办法进行这项工作。
答案 0 :(得分:0)
假设您可以控制“ runStep”功能,建议您修改它们以返回Either [Invalid,_]。这样,您可以像这样将它们组合成一个整体(我用Throwable代替Invalid,但是想法是一样的):
def raiseError(e: Throwable): Unit = println(e.getMessage)
def firstMethod(v: Int): Either[Throwable, Int] = Right(v * 2)
def secondMethod(v: Int) : Either[Throwable, Int] = Try(v / 0).toEither
def thirdMethod(v: Int): Either[Throwable, Int] = Right(v * 2)
val x = for {
first <- firstMethod(5)
second <- secondMethod(first)
third <- thirdMethod(second)
} yield third
x match {
case Left(err) => raiseError(err)
case Right(result) => println(result)
}
在这里,secondMethod引发了一个异常,因此ThirdMethod永远不会执行,这就是您要尝试的操作
答案 1 :(得分:0)
对于理解来说,只是flatMap
调用序列的语法糖。因此,不仅任何Scala代码都可以进入您的理解范围。以下是您尝试做的不合法Scala的事情之一:
//This does not compile because normal if-else statements are not valid inside a for comprehension
object Example1 {
def f(o: Option[Int]): Option[Int] = for {
x <- o
if (x < 0) "return some value"
else { //attempting to continue the for comprehension
y <- o
}
} yield ??? //what would we yield here?
}
a中的if
关键字用于后卫:
object Example2 {
def f(o: Option[Int]): Option[Int] = for {
x <- o
if x >= 0
} yield x
//f and f2 are equivalent functions
def f2(l: Option[Int]): Option[Int] = l.filter(_ >= 0)
}
但是那看起来并不像你想要的。您似乎在尝试运行每个步骤时都在跟踪异常。 Try
Monad正是这样做的,可以用于理解。请注意使用flatMap
调用而不是for理解的等效Scala代码。我建议您在尝试转换为更漂亮的理解语法之前,先使用所有嵌套的flatMap
调用编写函数,如果您遇到困难的话。检出this answer,以了解如何执行此操作的一些示例。
// myFunc1 is equiv to myFunc2 is equiv to myFunc3
// they only differ in syntax
object Example3 {
import scala.util.Try
def runStepA[A](in: A): Try[A] = ???
def runStepB[A](in: A): Try[A] = ???
def runStepC[A](in: A): Try[A] = ???
def myFunc1[A](input: A): Try[A] = for {
nonErrorResultA <- runStepA(input)
nonErrorResultB <- runStepB(nonErrorResultA)
nonErrorResultC <- runStepC(nonErrorResultB)
} yield nonErrorResultC
def myFunc2[A](input: A): Try[A] =
runStepA(input).flatMap {
nonErrorResultA => runStepA(nonErrorResultA).flatMap {
nonErrorResultB => runStepB(nonErrorResultB).flatMap {
nonErrorResultC => runStepC(nonErrorResultC)
}
}
}
def myFunc3[A](input: A): Try[A] =
runStepA(input).flatMap {
runStepA(_).flatMap {
runStepB(_).flatMap {
runStepC
}
}
}
}