有人可以举例说明如何使用ScalaZ Free monad吗?
例如,如果我有一个简单的State函数并想要应用它10,000次,我会得到StackOverflowError:
def setS(i: Int) :State[List[Int], Unit] = State { l => ( i::l, () ) }
val state = (1 to 10000).foldLeft( put(Nil :List[Int]) ) {
case (st, i) => st.flatMap(_ => setS(i))
}
state(Nil)
Run Code Online (Sandbox Code Playgroud)
据我所知,Free monad可以帮助避免这种情况.如何使用Free monad重写这段代码,不会导致堆栈溢出?
正如我在上面的评论中所说,将State计算提升到StateT[Free.Trampoline, S, A]似乎应该有效:
import scalaz._, Scalaz._, Free.Trampoline
def setS(i: Int): State[List[Int], Unit] = modify(i :: _)
val s = (1 to 10000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st.flatMap(_ => setS(i).lift[Trampoline])
}
s(Nil).run
Run Code Online (Sandbox Code Playgroud)
不幸的是,这仍然溢出堆栈,但正如 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
Run Code Online (Sandbox Code Playgroud)
我不确定这是为什么,并且我专门提出了一个关于差异的新问题,但这应该让您开始使用Free.