2012-03-25 18 views
10

Normalnie po utworzeniu Stream obiekt, szef będzie chętnie oceniane:Kiedy dokładnie obliczana jest głowa strumienia?

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

Jeśli stworzymy Stream do którego poprzedzić w tym samym oświadczeniu, wydaje się nieco zaskakujące, że szef nie jest oceniana przed konkatenacja. tj

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

(#:: jest tuż-asocjacyjne i jest metoda prepend na ConsWrapper, który jest niejawny klasa Stream.)

Jak to nie ocenia jego głowę przed poprzedzenie 0? Czy to jest, że Strumień Ogonowy (lub komórka po) nie istnieje na stercie, dopóki nie przyjmiemy wartości z powstałego strumienia? Ale jeśli tak, jak nazwać metodę #:: na obiekcie, który jeszcze nie istnieje?

+1

Proponuję użyć 'javap', aby zrozumieć, co się dzieje. –

+0

Odkryłem to patrząc na źródło (zakładając, że moja odpowiedź jest poprawna) –

Odpowiedz

7

-Xprint:typer jest twoim przyjacielem, za każdym razem, gdy chcesz zrozumieć, jak dokładnie kod jest oceniany lub typy są wnioskowane.

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) 

Parametrem consWrapper jest według nazwy. Więc nawet to działa:

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

+1 za użycie '-e'. Myślę, że jest tak mało używany w porównaniu do, powiedzmy, Perla. –

+0

Rozumiem. Ważne jest również to, że domyślna def od Stream do ConsWrapper jest by-name. 'niejawny def consWrapper [A] (strumień: => Strumień [A])'. Prawdopodobnie jest to spowodowane tym, że 'ConsWrapper' istnieje, a' # :: 'nie jest metodą bezpośrednio na' Stream': tak, że Stream nie musi być utworzony, aby wywołać tę metodę - po prostu dostajesz obiekt 'ConsWrapper' który zawiera podzbiór funkcjonalności. –

5

Głowa jest oceniana w momencie utworzenia strumienia.

Ale w twoim drugim przykładzie nie przekazujesz Streemy jako drugiego argumentu dla #::, że przekazujesz parametr nazwy, tzn. Całe wyrażenie Stream({println("evaluating 1"); 1} , 2, 3) nie jest w ogóle oceniane.