几周前Dragisa Krsmanovic提出了一个问题, 关于如何使用Scalaz 7中的自由单子来避免在这种情况下发生堆栈溢出(我稍微改编了他的代码):
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 刚刚 指出,使用应用程序 *>
而不是单调的 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中进行任何有趣操作的代价,但至少没有堆栈溢出。)
这里发生了什么?我不认为有什么原则上的差异,但实际上我不知道实现中可能正在发生什么,并且暂时没有时间挖掘。 但我很好奇,如果有人知道会很酷。
flatMap
重新定义了堆上的绑定方式,这意味着即使我们不丢弃该结果,在这里我们也是安全的? - Travis BrownApply
而不是Bind
。例如|@|
https://gist.github.com/drstevens/3ea464446ee59463af1e - drstevens