Когда точно оценивается глава Stream?
Обычно, если вы создаете объект Stream
, голова будет с нетерпением оценена:
scala> Stream( {println("evaluating 1"); 1} , 2, 3)
evaluating 1
res63: scala.collection.immutable.Stream[Int] = Stream(1, ?)
Если мы создадим Stream, к которому мы добавим тот же оператор, кажется немного удивительным, что голова не оценивается до конкатенации. то есть.
scala> 0 #:: Stream( {println("evaluating 1"); 1} , 2, 3)
res65: scala.collection.immutable.Stream[Int] = Stream(0, ?)
(#::
является право-ассоциативным и является методом prepend на ConsWrapper
, который является неявным классом Stream
.)
Как это не оценивает свою голову перед тем, как добавить 0? Неужели хвост Stream (или cons cell) не существует в куче, пока мы не примем значения из результирующего потока? Но если это так, как мы называем метод #::
для объекта, который еще не существует?
Ответы
Ответ 1
-Xprint:typer
является вашим другом, в любое время, когда вы хотите понять, как оценивается какой-либо код или типы.
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)
Параметр consWrapper
- это имя. Поэтому даже это работает:
scala> (1 #:: (sys.error("!!"): Stream[Int])).head
res1: Int = 1
Ответ 2
Голова оценивается в момент создания потока.
Но во втором примере вы не передаете Streem в качестве второго аргумента в #::
, вы передаете параметр по имени, т.е. полное выражение Stream( {println("evaluating 1"); 1} , 2, 3)
вообще не оценивается.