【问题标题】:Return final result from nested for-comprehensions processing stacked State and IO monads从嵌套的 for-comprehensions 处理堆叠的 State 和 IO monads 返回最终结果
【发布时间】:2019-10-30 22:19:56
【问题描述】:

作为question 的后续行动,我需要处理在processResult 中收集的所有结果。但是当我运行代码时,我从println(finalBusinessResult) 得到<function1>

编辑:似乎只处理第 1 步,仅此而已

问:如何让它从processResult返回结果

  case class BusinessState()
  trait BusinessResult
  case object KeepGoing extends BusinessResult
  case object StopNow extends BusinessResult
  type IOState[S, A] = StateT[IO, S, A]
  type BusinessIOState[A] = IOState[BusinessState, A]
  trait SomeSteps {
    def step1: BusinessIOState[Unit]
    def step2: BusinessIOState[BusinessState]
    def decisionStep: BusinessIOState[BusinessResult]
    def step3: BusinessIOState[BusinessResult]
    def step4: BusinessIOState[BusinessResult]
    def processResult(businessResult: BusinessResult*): BusinessIOState[BusinessResult]
    def toOpt(a: BusinessIOState[BusinessResult])
    : OptionT[BusinessIOState, BusinessResult] = {
      OptionT.liftF(a).filter(_ == KeepGoing)
    }
    def program: BusinessIOState[Unit] = (for {
      _ <- step1
      _ <- step2
      businessResult <- (for {
        businessResult1 <- toOpt(decisionStep)
        businessResult2 <- toOpt(step3)
        businessResult3 <- toOpt(step4)
      } yield processResult(businessResult1, businessResult2, businessResult3)).getOrElse(())
    } yield businessResult)
  }
  object Impl extends SomeSteps {
    def step1 = Monad[BusinessIOState].unit
    def step2 = Monad[BusinessIOState].pure(BusinessState())
    def decisionStep = StateT.liftF(IO { println("dS"); KeepGoing })
    def step3 = StateT.liftF(IO { println("3"); KeepGoing })
    def step4 = StateT.liftF(IO { println("4"); KeepGoing })
    def processResult(businessResult: BusinessResult*): BusinessIOState[BusinessResult] =
      StateT.liftF(IO { println("5"); KeepGoing })
  }

  def run(args: List[String]) = {

    val finalBusinessResult = for {
      businessResult <- Impl.program.runA(BusinessState())
    } yield businessResult

    println(finalBusinessResult)

    IO.pure(ExitCode.Success)
  }

【问题讨论】:

  • 似乎finalBusinessResult 返回了某种排序或函数值,请检查finalBusinessResulttype。您可能希望在打印之前调用该函数以获取值。
  • finalBusinessResult 似乎是一个IO[Unit],这是意料之中的,因为您明确告诉program 返回一个BusinessIOState[Unit]。如果你想让你的BusinessResults 可用,你将不得不在那里有一个不同的类型 - 并且在getOrElse 中有一个不同的默认值。此外,由于IO 是惰性异步,您将不得不通过例如显式运行finalBusinessResultunsafeRunSync 以获取实际执行的任何步骤。如果这样做,您将看到println 步骤触发器。

标签: scala functional-programming monads scala-cats


【解决方案1】:

在这些回复的帮助下,我设法让它正常工作。

  object StopIO extends IOApp {

  case class BusinessState()
  trait BusinessResult
  case object KeepGoing extends BusinessResult
  case object StopNow extends BusinessResult
  type IOState[S, A] = StateT[IO, S, A]
  type BusinessIOState[A] = IOState[BusinessState, A]

  trait SomeSteps {
    def step1: BusinessIOState[Unit]
    def step2: BusinessIOState[Unit]
    def decisionStep: BusinessIOState[BusinessResult]
    def step3: BusinessIOState[BusinessResult]
    def step4: BusinessIOState[BusinessResult]
    def processResult(businessResult: BusinessResult*): BusinessIOState[BusinessResult]

    def toOpt(a: BusinessIOState[BusinessResult]): OptionT[BusinessIOState, BusinessResult] = {
      OptionT.liftF(a).filter(_ == KeepGoing)
    }

    def program = (for {
      _ <- step1
      _ <- step2
      businessResult <- (for {
        businessResult1 <- toOpt(decisionStep)
        businessResult2 <- toOpt(step3)
        businessResult3 <- toOpt(step4)
        businessResult4 <- toOpt(processResult(businessResult1, businessResult2, businessResult3))
      } yield businessResult4).getOrElse(KeepGoing)
    } yield businessResult)
  }
  object Impl extends SomeSteps {
    def step1 = Monad[BusinessIOState].unit
    def step2 = Monad[BusinessIOState].pure(KeepGoing)
    def decisionStep = StateT.liftF(IO { println("dS"); KeepGoing })
    def step3 = StateT.liftF(IO { println("3"); KeepGoing })
    def step4 = StateT.liftF(IO { println("4"); KeepGoing })
    def processResult(businessResult: BusinessResult*) = StateT.liftF(IO { println("5"); KeepGoing })
  }

  def run(args: List[String]) = {

    val ioResult = for {
     businessResult <- Impl.program.runA(BusinessState())
    } yield businessResult

    println(ioResult.unsafeRunSync())

    IO.pure(ExitCode.Success)
  }
}

【讨论】:

    猜你喜欢
    • 2021-08-29
    • 2019-10-29
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 2016-06-02
    相关资源
    最近更新 更多