Reputation: 30027
I'm playing with scala streams.
Here is the stream of all integers starting from a given number.
I have added a println
to trace every call of from function.
def from(n: Int): Stream[Int] = n #:: from({ println(n); n + 1 })
val nats = from(0) //> nats : Stream[Int] = Stream(0, ?)
nats.take(4).toList //> 0
//| 1
//| 2
//| 3
//| res0: List[Int] = List(0, 1, 2, 3, 4)
As expected, this is the output of my scala worksheet. Then I have created the stream of all prime numbers.
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail.filter({ println( "---" ); _ % s.head != 0 }))
} //> sieve: (s: Stream[Int])Stream[Int]
val primes = sieve(from(2))//> primes : Stream[Int] = Stream(2, ?)
primes.take(4).toList //> 2
//| ---
//| 3
//| 4
//| ---
//| 5
//| 6
//| ---
//| res1: List[Int] = List(2, 3, 5, 7)
Here comes the question. I have made what in my opinion should be a little change, adding the x
parameter instead of _
placeholder. Surprisingly the output is quite different:
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail.filter(x => { println("---"); (x % s.head) != 0 }))
} //> sieve: (s: Stream[Int])Stream[Int]
val primes = sieve(from(2))//> primes : Stream[Int] = Stream(2, ?)
primes.take(4).toList //> 2
//| ---
//| 3
//| ---
//| 4
//| ---
//| ---
//| 5
//| ---
//| 6
//| ---
//| ---
//| ---
//| res1: List[Int] = List(2, 3, 5, 7)
I don't understand why all these repetitions. What's wrong in using the explicit parameter?
Upvotes: 2
Views: 3120
Reputation: 170713
The difference is because { println( "---" ); _ % s.head != 0 }
is short for { println( "---" ); x => x % s.head != 0 }
rather than { x => println( "---" ); x % s.head != 0 }
.
In the first case you first call println
and then return the function, so ---
is printed once per filter
call; in the second it's once per filter
call per element of the stream being filtered (and because sieve
is recursive and filters the stream again, you end up with multiple ---
for each element of the output).
Upvotes: 3
Reputation: 12783
Let's compare the argument to sieve in both cases, have a close look:
s.tail.filter( { println( "---" ); _ % s.head != 0 })
s.tail.filter(x => { println( "--- " + x ); (x % s.head) != 0 })
Do you see the difference in the println calls?
Now the outputs
First: Second:
//> 2 //> 2
//| --- //| --- 3
The crucial difference:
println( "---" )
println( "--- " + x )
In the 2nd case you are appending " "+x
right after the dashes and that's the exact difference between the cases.
Upvotes: 0