2012-09-18 18 views
10

निम्नलिखित स्थितिस्काला पूंछ पुनरावर्ती स्ट्रीम प्रोसेसर समारोह विशेषता में परिभाषित धारा सिर को

trait T { 

@tailrec 
def consume[A](as: Stream[A]): Unit = { 
    if (as.isEmpty)() 
    else consume(as.tail) 
    } 
} 

object O extends T 

बुला O.consume(Range(1, N).toStream)N काफी बड़ा के साथ, कार्यक्रम स्मृति से बाहर चला जाएगा, या कम से कम खपत होगी में संदर्भ रखती है ओ (एन) की आवश्यकता ओ (एन) के बजाय।

+0

भी देखें http://stackoverflow.com/questions/12529697/how-to-write-non-leaking-tail-recursive-stream-function-in-scala – ron

उत्तर

10

विशेषता के लिए पूंछ-पुनरावर्ती विधि उत्पन्न होती है। विशेषता के विस्तारक में विधि प्रविष्टि (यहां O) आगे की विशेषता के लिए कॉल को कॉल करें, लेकिन ऐसा करने पर, यह स्ट्रीम के प्रमुख का संदर्भ रखता है।

इस प्रकार विधि पूंछ-पुनरावर्ती है, लेकिन स्मृति अभी भी जारी नहीं की जा सकती है। उपाय: सीधे वस्तुओं में स्ट्रीम गुणों को परिभाषित न करें।

एक विकल्प स्केलज़ EphemeralStream है, जिसमें स्ट्रीम हेड और पूंछ के कमजोर संदर्भ हैं, और मांग पर उन्हें पुन: लागू करते हैं।

+0

[EphemeralStream] (https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/EphemeralStream.scala) –

2

एक साधारण कामकाज है।

import scala.annotation.tailrec 

trait T { 
    def consume[A](as: => Stream[A]): Unit = { 
    @tailrec 
    def loop[A](as: Stream[A]): Unit = { 
     if (as.isEmpty)() 
     else loop(as.tail) 
    } 
    loop(as) 
    } 
} 

object O extends T { 
    def main(args: Array[String]): Unit = 
    O.consume(Range(1, 1000000000).toStream) 
} 

फारवर्डर विधि कंप्यूटिंग एक अभिव्यक्ति परिणाम जो की एक धारा है एक समारोह के लिए एक संदर्भ का आयोजन करेगा: बस एक और समारोह है कि एक उप-नाम पैरामीटर के माध्यम से धारा प्राप्त करता है में अपने पूंछ पुनरावर्ती धारा उपभोक्ता लपेट :

public final class O$ implements T { 
    public static final MODULE$; 
    // This is the forwarder: 
    public <A> void consume(Function0<Stream<A>> as) { 
    T.class.consume(this, as); 
    } 
    . . .  

    public void main(String[] args) { 
    consume(new AbstractFunction0() { 
     public final Stream<Object> apply() { 
     return package..MODULE$.Range().apply(1, 1000000000).toStream(); 
     } 
    }); 
    } 
}