我在一起理解我们在一起组成多个操作。当每个步骤完成后,我需要使用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.
}
}
}
}
这不编译。我需要了解是否有办法使这项工作。
假设您可以控制“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,这是你要做的
因为理解只是一系列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?
}
for comprehension中的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 comprehension的等效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
}
}
}
}