Ich habe eine verschachtelte Strukturen, die ich mit einer Scalaz State Monade in XML umwandeln. Dies funktioniert gut, bis ich mit verschachtelten Multilevel-Strukturen umgehen muss. Hier ist ein vereinfachtes Beispiel ähnlich dem, was ich gerade mache. Angesichts der folgenden ADT:Wie geschachtelte Struktur beim Traversieren mit State Monad behandelt werden
sealed trait Nested
case object Leaf extends Nested
case class Foo(inner: Nested) extends Nested
case class Bar(inner: Nested) extends Nested
Ich schreibe einen Konverter Objekt den Zustand Monade mit (nehmen Scalaz7 und die folgenden Importe 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))
}
Je nach meinen Stack-Einstellungen convert(nested(1000)).apply(Parents(0, 0))
wird einen Stapelüberlauf verursachen im Umwandlungsprozess. (Höhere Werte nested
zum Überlaufen bringen, aber das ignoriert werden kann, da ich für diese Frage nur nested
erstellt.):
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)
Meine Frage ist - was ist der beste Weg, um den Stapelüberlauf in scalaz.stateT
zu vermeiden? Ich würde gerne die Zustands-Monade wie in meinem realen Beispiel verwenden, wenn die XML-Serialisierungslogik einfacher zu verfolgen und zu beheben ist (die tatsächlichen Eingabestrukturen sind JDI gespiegelt objects and arrays aus Live-Debugging-Sitzungen abgerufen und die inneren Werte sind verschachtelte Felder Werte).
Edit: die verschachtelte Stapel Ausgabe nehmen:
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)))
Ich erinnere mich an diesen Thread, den ich Lesezeichen hatte. Ich habe gerade bemerkt, dass du angefangen hast - https://groups.google.com/forum/#!topic/scalaz/QPUs6TWTAm4 Ich benutze StateT die ganze Zeit, aber am Ende mit etwas weniger elegant, wenn ich weiß, dass ich werde mehr als 200 oder so. – drstevens
Ich habe den StackOverflow nur durch Ausführen Ihrer verschachtelten Methode mit n = 1000 (ohne Verwendung von Scalaz-Code). – paradigmatic
@paradigmatisch, benutze das trampolinierte 'nested2', das ich gerade hinzugefügt habe. Ich vermute, die Antwort auf mein Problem ist auch auf Trampolin "konvertieren", aber das ist mir nicht klar, wie man es elegant macht. – huynhjl