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