使用 scalaz 的 free monad 时如何避免堆栈溢出? [英] How to avoid stack overflow when using scalaz's free monad?

查看:39
本文介绍了使用 scalaz 的 free monad 时如何避免堆栈溢出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前认为实现的部分目标是避免这个问题,所以也许我在做一些明显愚蠢的事情?

I had previously thought that part of the goal of the implementation was to avoid this very problem, so maybe I'm doing something obviously dumb?

这是一些代码:

    // Stack overflow
import scalaz._

sealed trait Command[T]
case class Wait(ms: Long) extends Command[Unit]

case object Evaluator extends (Command ~> Id.Id) {
  override def apply[T](cmd: Command[T]) = cmd match {
    case Wait(t)  => Thread.sleep(t)
  }
}

object Api {
  def sleep(ms: Long): Free.FreeC[Command, Unit] = Free.liftFC(Wait(ms))
}

val sleep: Free.FreeC[Command, Unit] =
  Api.sleep(1).flatMap { _ => sleep }

Free.runFC(sleep)(Evaluator)

注意:我意识到这很愚蠢:) 在实践中,我的命令类有很多命令,我有一个执行相同循环的命令......基本上,轮询一些状态,如果真中止,如果假,继续等待.

Note: I realize this is silly :) In practice, my command class has many commands, and I have a command which does this same loop...basically, poll some state, if true abort, if false, keep waiting.

我想避免这导致的堆栈溢出...我认为这已经被蹦床了,但我想我需要再次手动执行?在自由 monad 的思维方式中,有没有一种干净的方法来做到这一点?

I want to avoid the stack overflow that this causes... I THOUGHT this was already trampolined, but I guess I need to manually do it again? Is there a clean way to do it within the free monad way of thinking?

更新:

进一步思考这个问题,我认为问题不是 sleep Free Monad 而是我们在评估时绑定的 Id.Id monad ......所以我尝试了类似的东西:

Thinking further on this, I think the issue isn't the sleep Free Monad but rather the Id.Id monad taht we bind into on evaluation... so I tried something like:

case object Evaluator2 extends (Command ~> ({ type t[x] = Free[Id.Id, x] })#t) {
  override def apply[T](cmd: Command[T]) = cmd match {
    case Wait(t)  => Thread.sleep(t); Free.liftF[Id.Id, Unit](())
  }
}

Free.runFC[Command, ({ type t[x] = Free[Id.Id, x] })#t, Unit](sleep)(Evaluator2)(Free.freeMonad[Id.Id])

但问题在于它只会评估一个步骤.理想情况下,我希望 runFC 阻塞直到满足某些条件(或者在这种情况下,永远循环直到我杀死它,但没有堆栈溢出)

But the problem with this is that it will only evaluate one step. Ideally I would like runFC to block until some condition is satisfied (or in this case, to loop forever until I kill it, but without a stack overflow)

推荐答案

Id monad 不是蹦床.您最终会在 Id monad 的 bind 方法和自由 monad 的 foldMap 方法之间进行无限的相互递归.使用 TrampolineTask 而不是 Id.

The Id monad is not trampolined. You end up in an infinite mutual recursion between the bind method for the Id monad and the foldMap method for the free monad. Use Trampoline or Task instead of Id.

这篇关于使用 scalaz 的 free monad 时如何避免堆栈溢出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆