Как избежать переполнения стека при использовании бесплатной монады скалаза?

Раньше я думал, что часть цели реализации состоит в том, чтобы избежать этой самой проблемы, поэтому, возможно, я делаю что-то явно глупое?

Вот некоторый код:

    // 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 блокировался до тех пор, пока не будет выполнено какое-либо условие (или в этом случае, чтобы цикл продолжался до тех пор, пока я его не уничтожу, но без переполнения стека)

Ответы на вопрос(2)

Ваш ответ на вопрос