满足以下条件:运行运算的结果对于理解无效

时间:2019-02-28 01:28:12

标签: scala monads scala-cats for-comprehension

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

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

2 个答案:

答案 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
        }
      }
    }
}