匹配运行计算的结果是无效的for comprehension

问题描述 投票:0回答:2

我在一起理解我们在一起组成多个操作。当每个步骤完成后,我需要使用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.
      }
    }
  }
}

这不编译。我需要了解是否有办法使这项工作。

scala monads scala-cats for-comprehension
2个回答
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,这是你要做的


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?
}

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
        }
      }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.