Reputation: 1
I am playing with Scala's streams and I'm not sure I catch the idea. Let's consider following code
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))
executing this
val f = fun(Stream.from(7))
f take 14 foreach println
results with
7 8 9 10 ... up to 20
Let's say I understand this.
Now, changing slightly code (adding 2 to head)
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))
results in
9 10 11 ... up to 22
Again I think I understand. Problems starts with next example (d
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head / 2, fun(s.tail))
3 4 4 5 5 6 6 7 7 8 8 9 9 10
This I do not get, please explain why it results this way? Similar, subtracting also does not behave as I expect
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head - 2, fun(s.tail))
Output
5 6 7 8 9 10 ... up to 18
Upvotes: 0
Views: 131
Reputation: 7373
Ok, let's try and break it down...
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))
is a function that takes a Stream
and separates its head
and tail
, applies itself recursively on the tail
, and then recombines the two results with the cons
operator.
Since the head
is not touched during this operation, the Stream
is rebuilt element by element as it was before.
val f = fun(Stream.from(7))
f
it's the same as Stream.from(7)
[i.e. an infinite sequence of increasing integers starting from 7]
Printing f take 14
in fact shows that we have the first 14 numbers starting from 7 [i.e. 7,8,9,...,20]
What happens next is that, while rebuilding the stream with the cons
, each element is modified in some way
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))
This adds 2 to the head
before recombining it with the modified tail
. The latter is modified in the same way, its first element being added to 2 and then recombined to its own tail
, and so own.
If we assume again that s
contains the number from 7 on, what happens looks like
fun(s) = cons(7 + 2, cons(8 + 2, cons(9 + 2, ... ad infinitum ... )))))
This is the same as adding 2 to each and every element of the stream s
.
The code confirms that by printing "9 to 22", which is exactly "7 to 20" with 2 added to every element.
The others examples are analogous:
Stream
is typed with Int
values) Upvotes: 0
Reputation: 26486
Is it more intuitive if you think of it as mapping the Stream
?
scala> val s1 = Stream.from(10)
s1: scala.collection.immutable.Stream[Int] = Stream(10, ?)
scala> val s2 = s1 map (_ * 2)
s2: scala.collection.immutable.Stream[Int] = Stream(20, ?)
scala> s2.take(5).toList
res0: List[Int] = List(20, 22, 24, 26, 28)
scala> val s3 = s1 map (_ / 2)
s3: scala.collection.immutable.Stream[Int] = Stream(5, ?)
scala> s3.take(5).toList
res1: List[Int] = List(5, 5, 6, 6, 7)
scala> val s4 = s1 map (_ - 2)
s4: scala.collection.immutable.Stream[Int] = Stream(8, ?)
scala> s4.take(5).toList
res2: List[Int] = List(8, 9, 10, 11, 12)
Upvotes: 0
Reputation: 8463
Given your "take": 7 8 9 10 ... up to 20
,
what happens when you + 2
on each element?
what happens when you / 2
on each element (int
arithmetic)?
what happens when you - 2
on each element?
Upvotes: 1