我有一個嵌套結構,我正在使用scalaz狀態monad將其轉換爲XML。這工作得很好,直到我不得不處理多級嵌套結構。這裏是一個簡化的例子,類似於我正在做的事情。鑑於以下ADT:如何在使用狀態monad遍歷時處理嵌套結構
sealed trait Nested
case object Leaf extends Nested
case class Foo(inner: Nested) extends Nested
case class Bar(inner: Nested) extends Nested
我寫的使用狀態單子轉換器對象(假設Scalaz7及以下進口import scalaz.{Node => _, _}; import Scalaz._; import scala.xml._
):
case class Parents(foos: Int, bars: Int)
type ParentsS[X] = State[Parents, X]
def convertFoo(foo: Foo): ParentsS[Seq[Node]] = for {
parents <- init[Parents]
_ <- put[Parents](Parents(parents.foos + 1, parents.bars))
inner <- convert(foo.inner)
_ <- put[Parents](parents)
} yield <foo count={ parents.foos.toString }/>.copy(child=inner)
def convertBar(bar: Bar): ParentsS[Seq[Node]] = for {
parents <- init[Parents]
_ <- put[Parents](Parents(parents.foos, parents.bars + 1))
inner <- convert(bar.inner)
_ <- put[Parents](parents)
} yield <bar count={ parents.bars.toString }/>.copy(child=inner)
def convert(nested: Nested): ParentsS[Seq[Node]] = nested match {
case Leaf => Seq[Node]().point[ParentsS]
case [email protected](_) => convertFoo(foo)
case [email protected](_) => convertBar(bar)
}
def nested(n: Int): Nested =
if (n == 0) Leaf
else {
if (n % 2 == 0) Bar(nested(n - 1))
else Foo(nested(n - 1))
}
根據我的堆棧設置,convert(nested(1000)).apply(Parents(0, 0))
會導致堆棧溢出在轉換過程中。 (超出該值會nested
溢出,但是這可能因爲我剛剛創建nested
這個問題被忽略。):
at scalaz.IdInstances$$anon$1.bind(Id.scala:20)
at scalaz.StateT$$anonfun$flatMap$1.apply(StateT.scala:48)
at scalaz.StateT$$anon$7.apply(StateT.scala:72)
at scalaz.StateT$$anonfun$flatMap$1.apply(StateT.scala:48)
at scalaz.StateT$$anon$7.apply(StateT.scala:72)
at scalaz.StateT$$anonfun$flatMap$1$$anonfun$apply$2.apply(StateT.scala:49)
at scalaz.StateT$$anonfun$flatMap$1$$anonfun$apply$2.apply(StateT.scala:48)
我的問題是 - 什麼是避免scalaz.stateT
堆棧溢出的最佳方式?如果讓XML序列化邏輯更易於跟蹤和排除故障(實際輸入結構是從實時調試會話中檢索到的JDI鏡像objects and arrays,內部值是嵌套字段值),我想繼續使用狀態monad。
編輯:取出嵌套堆棧問題:
import util.control.TailCalls
def nested2(n: Int, acc: Nested = Leaf): TailCalls.TailRec[Nested] =
if (n == 0) TailCalls.done(acc)
else TailCalls.tailcall(nested2(n - 1, if (n % 2 == 0) Bar(acc) else Foo(acc)))
我想起了我已經添加書籤的這個主題。我剛剛注意到你開始使用它 - https://groups.google.com/forum/#!topic/scalaz/QPUs6TWTAm4 我一直都在使用StateT,但是當我知道我將要成爲一個不太優雅的東西時遍歷200多個左右。 – drstevens
我得到了StackOverflow,只需運行n = 1000的嵌套方法(不使用任何Scalaz代碼)。 – paradigmatic
@paradigmatic,使用我剛剛添加的蹦牀'nested2'。我懷疑我的問題的答案也是蹦牀'轉換',但這並不明顯,我如何優雅地做到這一點。 – huynhjl