The following code prints "*1". What's mystifying is if I remove the comment it returns "*4" which is what I was expecting
var max = 0
lazy val list: Stream[Int] = 1 #:: Stream.from(2)
list.takeWhile {
x =>
max = x
x < 4
}//.foreach(println)
println("*" + max)
First of all: the lazy
in your second line isn't doing anything—you can remove it and get the same result.
More importantly: takeWhile
is actually lazy, in that it just returns another Stream
, and nothing past the head of that stream will be evaluated until it's needed. Consider the following:
val s = Stream.from(1).takeWhile(_ > 0)
You and I know that s
is going to be an infinite stream, but if we fire up the REPL and type this in, it's perfectly happy to evaluate it:
scala> val s = Stream.from(1).takeWhile(_ > 0)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
The same thing is happening in your example: the (Int) ⇒ Boolean
that you've passed to takeWhile
isn't going to get fed any elements beyond the head of the stream, until something like your foreach
makes that necessary.
You can see this even more dramatically by adding something like a println
inside of the takeWhile
predicate:
scala> val s = Stream.from(1).takeWhile { x => println("Checking: " + x); x < 4 }
Checking: 1
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val l = s.toList
Checking: 2
Checking: 3
Checking: 4
l: List[Int] = List(1, 2, 3)
Clearly the predicate only gets called for the head of the stream, until we force the evaluation of the rest of the stream by calling toList
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With