2012-12-17 17 views
7

के साथ ट्रैवर्स करते समय नेस्टेड संरचना को कैसे संभालें I have a nested संरचनाएं हैं जिन्हें मैं स्केलाज़ राज्य मोनैड का उपयोग करके एक्सएमएल में परिवर्तित कर रहा हूं। यह तब तक अच्छा काम करता है जब तक मुझे बहु-स्तर के नेस्टेड संरचनाओं से निपटना पड़े। मैं जो कर रहा हूं उसके समान एक सरलीकृत उदाहरण यहां दिया गया है।राज्य मोनैड

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 में ढेर अतिप्रवाह से बचने के लिए है? मैं अपने असली उदाहरण के रूप में राज्य मोनैड का उपयोग करना जारी रखना चाहूंगा यदि एक्सएमएल सीरियलाइजेशन तर्क का पालन करना आसान है और समस्या निवारण (वास्तविक इनपुट संरचनाएं जेडीआई प्रतिबिंबित हैं objects and arrays लाइव डिबगिंग सत्रों से पुनर्प्राप्त और आंतरिक मान घोंसला वाले फ़ील्ड मान हैं)।

संपादित करें: नेस्टेड ढेर मुद्दा बाहर निकालने के लिए:

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))) 
+0

मुझे इस थ्रेड की याद दिलाई गई है जिसे मैंने बुकमार्क किया था। मैंने अभी देखा है कि आपने इसे शुरू किया - https://groups.google.com/forum/#!topic/scalaz/QPUs6TWTAm4 मैं हर समय स्टेटटी का उपयोग करता हूं, लेकिन जब मुझे पता है कि मैं होने वाला हूं तो कुछ कम सुरुचिपूर्ण 200 से अधिक या तोड़ने। – drstevens

+0

मुझे अपने नेस्टेड विधि को n = 1000 (किसी भी स्कालज़ कोड का उपयोग किए बिना) चलाकर केवल स्टैक ओवरफ्लो मिला। – paradigmatic

+1

@paradigmatic, मैंने अभी जोड़ा trampolined 'nested2' का उपयोग करें। मुझे संदेह है कि मेरी समस्या का जवाब 'कन्वर्ट' को ट्रामपोलिन करना भी है, लेकिन यह स्पष्ट नहीं है कि इसे सुंदर तरीके से कैसे किया जाए। – huynhjl

उत्तर

4

ट्रेम्पोलिनिंग मदद कर सकते हैं ढेर अतिप्रवाह यहाँ से बचें।

sealed trait Nested 
case object Leaf extends Nested 
case class Foo(inner: Nested) extends Nested 
case class Bar(inner: Nested) extends Nested 

import scalaz.{Node => _, _}; import Scalaz._; 
import scala.util.control.TailCalls, scala.xml._ 

case class Parents(foos: Int, bars: Int) 

def nested(n: Int, acc: Nested = Leaf): TailCalls.TailRec[Nested] = 
    if (n == 0) TailCalls.done(acc) else TailCalls.tailcall(
    nested(n - 1, if (n % 2 == 0) Bar(acc) else Foo(acc)) 
) 

कुछ थोड़ा अलग प्रकार उपनाम: एक ही सेटअप के लिए सबसे पहले

val monadState = MonadState[TrampolinedState, Parents] 
import monadState._ 

और बाकी:

type TrampolinedState[S, A] = StateT[Free.Trampoline, S, A] 
type ParentsS[A] = TrampolinedState[Parents, A] 

हम सुविधा के लिए हमारे MonadState उदाहरण के तरीकों आयात करेंगे वास्तव में थोड़ा और संक्षिप्त है, क्योंकि हमें put, आदि पर टाइप पैरामीटर की आवश्यकता नहीं है .:

def convertFoo(foo: Foo): ParentsS[Seq[Node]] = for { 
    parents <- init 
    _ <- put(Parents(parents.foos + 1, parents.bars)) 
    inner <- convert(foo.inner) 
    _ <- put(parents) 
} yield <foo count={ parents.foos.toString }/>.copy(child=inner) 

def convertBar(bar: Bar): ParentsS[Seq[Node]] = for { 
    parents <- init 
    _ <- put(Parents(parents.foos, parents.bars + 1)) 
    inner <- convert(bar.inner) 
    _ <- put(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) 
} 

अब हम सिर्फ चलाने (उदाहरण के लिए) के बाद:

convert(nested(2000).result).apply(Parents(0, 0)).run 

कि इस स्थान से दूर काम करता है कि वेनिला State समाधान मेरी मशीन पर घुट शुरू कर दिया।

+0

धन्यवाद, यह पूरी तरह से काम किया! – huynhjl

+0

धन्यवाद! इच्छा है कि मैं यह +10 कर सकता था। मैंने कुछ स्थानों पर एसओ को रोकने के लिए इस सामान्य दृष्टिकोण का उपयोग किया जहां मैं पहले 'सूची [ए] .traverse [({टाइप λ [α] = राज्य [एस, α]}) # λ, ए] 'प्रदर्शन कर रहा था। स्कालाज़ 6 के साथ इस काम को कैसे बनाया जाए, यह जानने में थोड़ी देर लग गई, लेकिन मुझे अंततः यह मिला। – drstevens

संबंधित मुद्दे