Я раньше думал, что часть цели реализации заключается в том, чтобы избежать этой самой проблемы, так что, может быть, я делаю что-то явно немое?Как избежать переполнения стека при использовании бесплатной монады Скалаза?
Вот код:
// 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)
Примечания: Я понимаю, что это глупо :) На практике, моя команда класс имеет много команд, и у меня есть команда, которая делает этот же цикл ... в основном, опросить какое-то состояние, если true abort, если false, продолжать ждать.
Я хочу избежать переполнения стека, что это вызывает ... Я ДУМАЮ, что это уже батут, но я думаю, мне нужно вручную сделать это снова? Есть ли чистый способ сделать это в рамках свободного монадского мышления?
Update:
Думая далее на этом, я думаю, что проблема не сон Free Монада, а скорее Id.Id монада TAHT мы связываем в основе оценки ... так что я пытался что-то вроде:
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 блокировался до тех пор, пока не будет выполнено какое-либо условие (или, в этом случае, цикл навсегда, пока я не убью его, но без переполнения стека)