I'm using scalaz' Monad.whileM_ to implement a while loop in a functional way as follows:
object Main {
  import scalaz._
  import Scalaz._
  import scala.language.higherKinds
  case class IState(s: Int)
  type IStateT[A] = StateT[Id, IState, A]
  type MTransT[S[_], A] = EitherT[S, String, A]
  type MTrans[A] = MTransT[IStateT, A]
  def eval(k: Int): MTrans[Int] = {
    for {
      state <- get[IState].liftM[MTransT]
      _ <- put(state.copy(s = (state.s + 1) % k)).liftM[MTransT]
    } yield (k + 1)
  }
  def evalCond(): MTrans[Boolean] = {
    for {
      state <- get[IState].liftM[MTransT]
    } yield (state.s != 0)
  }
  def run() = {
    val k = 10
    eval(k).whileM_(evalCond()).run(IState(1))
  }
}
While this works for small k, it results in a StackOverflow error for large k (e.g. 1000000). Is there a way to trampoline whileM_ or is there a better way to be stack safe?
                        
Use
scalaz.Free.Trampolineinstead ofscalaz.Id.Id.The state operations used here return
State[S, A]which is just an alias forStateT[Id, S, A]. You need to use thelift[M[_]]function defined onStateTto liftStateT[Id, S, A]toStateT[Trampoline, S, A].Finally, calling
.run(IState(1))now results inTrampoline[(IState, String \/ Unit)]. You must additionallyrunthis as well.