Scalaz中State和Free monad的例子

时间:2014-05-31 00:27:41

标签: scala scalaz

有人可以举例说明如何使用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)

据我了解,免费monad可以帮助避免这种情况。如何使用Free monad重写这段代码,不会导致堆栈溢出?

1 个答案:

答案 0 :(得分:4)

正如我在上面的评论中所说,将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

不幸的是,这仍然会溢出堆栈,但正如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

我不确定为什么会这样,而且我asked a new question具体说明了差异,但这应该让你开始Free