2012-03-25 3 views
10

Normalerweise:Wann genau wird der Kopf eines Streams ausgewertet? wenn Sie ein <code>Stream</code>-Objekt erstellen, wird der Kopf mit Spannung ausgewertet

scala> Stream({println("evaluating 1"); 1} , 2, 3) 
evaluating 1 
res63: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

Wenn wir einen Bach, auf die wir in der gleichen Aussage voranstellen, übernimmt es etwas überraschend scheint, dass der Kopf nicht vor ausgewertet wird die Verkettung. d.h.

scala> 0 #:: Stream({println("evaluating 1"); 1} , 2, 3) 
res65: scala.collection.immutable.Stream[Int] = Stream(0, ?) 

(#:: ist rechtsassoziativ und ist das Verfahren auf prepend ConsWrapper, die eine implizite Klasse von Stream.)

Wie dies den Kopf nicht bewerten, bevor die 0 Voranstellen? Ist der Tail Stream (oder die Cons-Zelle) nicht auf dem Heap vorhanden, bis wir Werte aus dem resultierenden Stream ziehen? Aber wenn ja, wie rufen wir die Methode #:: für ein Objekt auf, das noch nicht existiert?

+1

Ich schlage vor, Sie 'javap' zu verwenden, um zu verstehen, was vor sich geht. –

+0

Ich habe herausgefunden, dass die Quelle (vorausgesetzt, meine Antwort ist korrekt) –

Antwort

7

-Xprint:typer ist Ihr Freund, jederzeit, wenn Sie genau verstehen möchten, wie einige Code ausgewertet oder Typen abgeleitet werden.

scala -Xprint:typer -e '0 #:: Stream({println("evaluating 1"); 1} , 2, 3)' 

val x$1: Int = 0; 
Stream.consWrapper[Int](Stream.apply[Int]({ 
    println("evaluating 1"); 
    1 
}, 2, 3)).#::(x$1) 

Der Parameter consWrapper ist by-name. Also auch das funktioniert:

scala> (1 #:: (sys.error("!!"): Stream[Int])).head 
res1: Int = 1 
+0

+1 für die Verwendung von "-e". Ich denke, es ist so wenig benutzt, verglichen mit, sagen wir, Perls. –

+0

Ich verstehe es jetzt. Wichtig ist auch, dass das implizite Def von Stream zu ConsWrapper By-Name ist. 'implizit def consWrapper [A] (stream: => Stream [A])'. Dies ist vermutlich der Grund, warum 'ConsWrapper' existiert und' # :: 'ist keine direkte Methode für' Stream': Damit der Stream nicht erzeugt werden muss, um diese Methode aufzurufen, erhalten Sie nur ein 'ConsWrapper'-Objekt Das enthält die Teilmenge der Funktionalität. –

5

Der Kopf wird in dem Moment ausgewertet, in dem der Stream erstellt wird.

In Ihrem zweiten Beispiel übergeben Sie keinen Streem als zweites Argument an #:: übergeben Sie einen Parameter nach Name, d. H. Der vollständige Ausdruck Stream({println("evaluating 1"); 1} , 2, 3) wird überhaupt nicht ausgewertet.