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?
Here is some code:
// 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.
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?
Update:
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])
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)