几周前Dragisa Krsmanovic在这里问了一个问题,关于如何在 Scalaz 7 中使用 free monad 来避免这种情况下的堆栈溢出(我对他的代码做了一些修改):
import scalaz._, Scalaz._
def setS(i: Int): State[List[Int], Unit] = modify(i :: _)
val s = (1 to 100000).foldLeft(state[List[Int], Unit](())) {
case (st, i) => st.flatMap(_ => setS(i))
}
s(Nil)
我认为只需将蹦床举起来就StateT
可以了:
import Free.Trampoline
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st.flatMap(_ => setS(i).lift[Trampoline])
}
s(Nil).run
但它仍然会破坏堆栈,所以我只是将其发布为评论。
Dave Stevens刚刚指出,使用 applicative*>
而不是 monadic 的排序flatMap
实际上工作得很好:
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st *> setS(i).lift[Trampoline]
}
s(Nil).run
(嗯,它当然超级慢,因为这是你在 Scala 中做类似这样有趣的事情所付出的代价,但至少没有堆栈溢出。)
这里发生了什么?我认为这种差异可能没有原则上的原因,但我真的不知道实施中会发生什么,并且目前没有时间进行挖掘。但我很好奇,如果其他人知道会很酷。