When exactly is the head of a Stream evaluated?

╄→尐↘猪︶ㄣ 提交于 2019-12-21 03:54:10

问题


Normally if you create a Stream object, the head will be eagerly evaluated:

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

If we create a Stream to which we prepend in the same statement, it seems slightly surprising that the head is not evaluated prior to the concatenation. i.e.

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

(#:: is right-associative and is the prepend method on ConsWrapper, which is an implicit class of Stream.)

How does this not evaluate its head before prepending the 0? Is it that the tail Stream (or cons cell) does not exist on the heap until we take values from the resultant Stream? But if so, how do we call the #:: method on an object that doesn't exist yet?


回答1:


-Xprint:typer is your friend, any time you want to understand exactly how some code is evaluated or types are inferred.

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)

The parameter of consWrapper is by-name. So even this works:

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



回答2:


The head is evaluated in the moment the Stream is created.

But in you second example you don't pass a Streem as the second argument to #:: you pass a by name parameter, i.e. the complete expression Stream( {println("evaluating 1"); 1} , 2, 3) isn't evaluated at all.



来源:https://stackoverflow.com/questions/9857103/when-exactly-is-the-head-of-a-stream-evaluated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!