2012-03-25 18 views
10

Normalmente, si se crea un objeto Stream, la cabeza se ansiosamente evaluó:¿Cuándo se evalúa exactamente el jefe de un flujo?

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

Si creamos una corriente a la que anteponer en la misma instrucción, parece un poco sorprendente que la cabeza no se evalúa antes de la concatenación. es decir,

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

(#:: es asociativo por la derecha y es el método anteponer el ConsWrapper, que es una clase implícita de Stream.)

¿Cómo funciona esto no evalúa su cabeza antes de anteponer el 0? ¿Es que la cola Stream (o cons cell) no existe en el montón hasta que tomemos valores de la secuencia resultante? Pero si es así, ¿cómo llamamos al método #:: en un objeto que aún no existe?

+1

Le sugiero que use 'javap' para entender lo que está pasando. –

+0

Lo descubrí mirando la fuente (asumiendo que mi respuesta es correcta) –

Respuesta

7

-Xprint:typer es su amigo, cada vez que desee comprender exactamente cómo se evalúa algún código o se deducen tipos.

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) 

El parámetro de consWrapper es un nombre. Así que incluso esto funciona:

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

+1 para usar '-e'. Creo que se usa tan poco en comparación con, digamos, Perl. –

+0

Lo entiendo ahora. También es importante que la definición implícita de Stream a ConsWrapper sea por nombre. 'implicit def consWrapper [A] (stream: => Stream [A])'. Esto es presumiblemente por qué 'ConsWrapper' existe, y' # :: 'no es un método en' Stream' directamente: por lo que no es necesario crear el flujo para llamar a este método; simplemente obtienes un objeto 'ConsWrapper' que contiene el subconjunto de funcionalidad. –

5

La cabeza se evalúa en el momento en que se crea la secuencia.

Pero en su segundo ejemplo, no pasa un Streem como segundo argumento al #::, pasa un parámetro por nombre, es decir, la expresión completa Stream({println("evaluating 1"); 1} , 2, 3) no se evalúa en absoluto.

Cuestiones relacionadas