1

Can someone please explain the following output from the REPL?

I'm defining 2 (infinite) Streams that are otherwise identical in their definition except that map is preceded by . (period) in one definition and a _ _ (space) in the other.

I can see that this would cause map to bind differently, but what happens to the 1 in the output from the second definition?

Thanks.

scala> lazy val infinite: Stream[Int] = 1 #:: infinite.map(_+1)
infinite: Stream[Int] = <lazy>

scala> val l = infinite.take(10).toList.mkString(",")
l: String = 1,2,3,4,5,6,7,8,9,10

scala> lazy val infinite2: Stream[Int] = 1 #:: infinite2 map(_+1)
infinite2: Stream[Int] = <lazy>

scala> val l2 = infinite2.take(10).toList.mkString(",")
l2: String = 2,3,4,5,6,7,8,9,10,11

2 Answers2

11

It's about method associativity. This:

1 #:: infinite.map(_+1)

is quite straightforward while this:

1 #:: infinite2 map(_+1)

is interpreted by the compiler as:

(1 #:: infinite2) map(_+1)

1 #:: infinite2 is your desired stream, but before you return it, you apply lazy transformation adding one to every item. This explains why 1 never appears as a result - after transformation it becomes 2.

For more details see: Operator precedence in Scala. Since # is not a special character, it is treated equally with map, thus methods are evaluated from left to right.

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
1

In the infinite2 case, what you've expressed is equivalent to the following:

lazy val infinite2: Stream[Int] = (1 #:: infinite2) map(_ + 1)

Since the stream starts with 1, the map will add 1 to the first element.

yakshaver
  • 2,472
  • 1
  • 18
  • 21