2012-09-18 27 views
10

O.consume(Range(1, N).toStream) yeterince büyük N ile, program bellek üzerinden çalışır, ya da en azından tüketecektir çağrı aşağıdaki durumdaScala kuyruk özyinelemeli Akış işlemci fonksiyonu akış kafa için

trait T { 

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

object O extends T 

olarak başvuru içerir O (N) yerine gerekli O (1).

+0

bakınız http://stackoverflow.com/questions/12529697/how-to-write-non-leaking-tail-recursive-stream-function-in-scala – ron

cevap

10

Kuyruk özyineleme yöntemi, özellik için üretildi. Özelliğin içerisindeki yöntem girişi (burada O) aramayı yöntemin yöntemine yönlendirir, ancak bunu yaparken Akımın başına bir referans tutar. Böylece, yöntem kuyruk özyinelemesine karşın, bellek yine de serbest bırakılamaz. Çözüm: Aktarım işlevlerini, yalnızca doğrudan nesneler içinde, özelliklerde tanımlamayın.

Bir alternatif, scalazın EphemeralStream, akış kafasına ve kuyruğa zayıf referanslar içerir ve bunları talep üzerine yeniden derler.

+0

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

2

Basit bir çözüm var.

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) 
} 

iletici yöntem, bir ifadeyi bir akım olan sonucunu işlem bir işlev başvuru tutacaktır: sadece bir yan adı parametresi ile akışı içine alan bir diğer fonksiyonu da kuyruk özyinelemeli akış tüketici sarmak :

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(); 
     } 
    }); 
    } 
}