scalaz Free Monad控件中断和暂停一系列计算
我有一个计算链,它改变了上下文的状态:scalaz Free Monad控件中断和暂停一系列计算,scala,monads,scalaz,Scala,Monads,Scalaz,我有一个计算链,它改变了上下文的状态: case class Context(...) type Step = (Context => Context) val step1: Step = ctx => { ctx.copy(...) } val step2: Step val step3: Step // ... val stepN: Step val chain = List(step1, step2, step3, ..., stepN).toStream 我想引入计算的返回
case class Context(...)
type Step = (Context => Context)
val step1: Step = ctx => { ctx.copy(...) }
val step2: Step
val step3: Step
// ...
val stepN: Step
val chain = List(step1, step2, step3, ..., stepN).toStream
我想引入计算的返回值来控制该链的流量:
trait Cont
case class Break[Context](ctx: Context) extends Cont
case class Pause[Context](ctx: Context) extends Cont
case class Continue[Context](ctx: Context) extends Cont
中断-表示在执行当前步骤后取消链
暂停-意味着在执行当前步骤后暂停计算,能够在以后继续下一步并检查其是否可恢复
继续-表示流的正常继续
每个步骤都应该返回Cont中包装的上下文的当前值
目前,我正在通过展开步骤流val chain:stream[Cont[Step]]并检查chain.isEmpty和chain.head来检查是否还有一些计算
如何在scalaz中使用免费的单子呢?您可以通过使用scalaz的延续单子scalaz.Cont来实现这一点 遗憾的是,没有关于如何使用scalaz.Cont的文档和示例。所以,为了对连续体有一个基本的了解,以及它们的用途,我们来看看 在 . 对于使用免费monad,建议阅读Debassh Ghosh的功能和反应域建模。 使用continuations的本质是,我们不会从计算中返回值,而是将控制传递给continuation,通常使用变量k,continuation指定接下来会发生什么 这就是说,让我们看看您的具体示例中的情况: 首先是一些类型定义;请注意,下一步是一个Continuation函数,它接受上下文并返回Return类型的内容 然后定义一些类型来控制计算链中的流;请注意,Pause还返回一个Continuation,因为我们希望以后能够继续计算
trait Return
case class Break(context: Context) extends Return
case class Pause(context: Context, continuation: Continuation) extends Return
case class Done(context: Context) extends Return
接下来,我们将我们的步骤定义为类,以便能够将它们与免费的monad一起使用
trait Step[A]
case class Step1(c: Context) extends Step[Context]
case class Step2(c: Context) extends Step[Context]
case class Step3(c: Context) extends Step[Context]
。。。并将它们提升到自由单子的上下文中
type Command[A] = Free[Step, A]
protected implicit def liftStep[A](step: Step[A]): Command[A] =
Free.liftF(step)
def step1(c: Context): Command[Context] = Free.liftF(Step1(c))
def step2(c: Context): Command[Context] = Free.liftF(Step2(c))
def step3(c: Context): Command[Context] = Free.liftF(Step3(c))
现在我们建立计算链;请注意,我们将上一次计算的结果(如c1)传递到下一次计算,如步骤2C1;如果这种情况更隐晦地发生,那么可能应该考虑使用状态monad将状态从continuation传递到continuation
val script = for {
c0 <- Free.point(Context(0))
c1 <- step1(c0)
c2 <- step2(c1)
c3 <- step3(c2)
} yield c3
val process: Cont[Return, Context] = script.foldMap(step)
使用解释器步骤运行脚本以获得延续
val script = for {
c0 <- Free.point(Context(0))
c1 <- step1(c0)
c2 <- step2(c1)
c3 <- step3(c2)
} yield c3
val process: Cont[Return, Context] = script.foldMap(step)
运行延续过程;请注意,run方法需要一个Continuation,它将是最后一个计算步骤的Continuation,即c将是步骤3中的Context3
最后,编写一些代码来执行整个链,如果计算刚刚暂停,则继续;如果结果是Break或Done,则停止
var continue = true
do {
continue = result match {
case Pause(c, continuation) =>
println(s"Pause: $c")
result = continuation(c)
true
case Break(c) =>
println(s"Break: $c")
false
case Done(c) =>
println(s"Done: $c")
false
}
} while(continue)
结果是:
Pause: Context(2)
Done: Context(3)
Pause: Context(2)
Done: Context(3)