gpt4 book ai didi

scala - 在使用 State 和 IO 的堆叠 monad 时停止理解中流

转载 作者:行者123 更新时间:2023-12-01 06:55:01 25 4
gpt4 key购买 nike

在这个 Scala 示例中,我需要在结果为 StopNow 时停止,我需要在调用 decisionStep 之后执行此操作。

我该怎么做?

  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 program = for {
_ <- step1
businessState <- step2

businessResult <- decisionStep

businessResult1 <- step3
businessResult2 <- step4
} yield()
}

最佳答案

如果你想保持状态,那么你可以将另一个 monad 转换器添加到混合中,即 OptionT,用于短路。包含可能返回 StopNow 的所有步骤的整个 block 然后被提升到 OptionT,最后使用 getOrElse 返回到 BusinessIOState :

import cats._
import cats.data._
import cats.syntax._
import cats.effect._

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[BusinessState]
def decisionStep: BusinessIOState[BusinessResult]
def step3: BusinessIOState[BusinessResult]
def step4: BusinessIOState[BusinessResult]

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

def program: BusinessIOState[Unit] = (for {
_ <- step1
businessState <- step2
_ <- (for {
_ <- toOpt(decisionStep)
_ <- toOpt(step3)
_ <- toOpt(step4)
} yield ()).getOrElse(())
} yield ())
}

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"); StopNow })
def step4 = StateT.liftF(IO { println("4"); KeepGoing })
}

def run(args: List[String]) = for {
_ <- Impl.program.runA(BusinessState())
} yield ExitCode.Success
}

输出是:

dS
3

注意 4 没有出现,程序提前停止,因为 step3 返回一个 StopNow


您可能想知道为什么不使用 MonadError[IO, Throwable] 的功能进行短路,因为 IO 已经可以处理因抛出而停止的计算异常(exception)。它可能看起来像这样:

import cats._
import cats.data._
import cats.syntax._
import cats.effect._

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[BusinessState]
def decisionStep: BusinessIOState[BusinessResult]
def step3: BusinessIOState[BusinessResult]
def step4: BusinessIOState[BusinessResult]

def raiseStop(a: BusinessIOState[BusinessResult])
: BusinessIOState[Unit] = {
a.flatMap {
case KeepGoing => StateT.liftF(IO.unit)
case StopNow => StateT.liftF(
MonadError[IO, Throwable].raiseError(new Exception("stop now"))
)
}
}

def program = (for {
_ <- step1
businessState <- step2
_ <- raiseStop(decisionStep)
_ <- raiseStop(step3)
_ <- raiseStop(step4)
} yield ())
}

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"); StopNow })
def step4 = StateT.liftF(IO { println("4"); KeepGoing })
}

def run(args: List[String]) = for {
_ <- Impl.program.runA(BusinessState()).handleErrorWith(_ => IO.unit)
} yield ExitCode.Success
}

同样,输出是:

dS
3

我认为它与 OptionT 版本相比既不短也不清晰,而且它还有一个缺点,即在 StopNow 结果的情况下,状态不会通过正确打开,但所有内容都被删除,并且 () 在“世界尽头”返回。这有点类似于对控制流使用异常,但还有一个缺点,即它所能做的就是完全退出整个程序。所以,我可能会尝试使用 OptionT

关于scala - 在使用 State 和 IO 的堆叠 monad 时停止理解中流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56622043/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com