Reputation: 2424
I have a piece of code that is calculating some series:
object Problem7 extends App {
lazy val ps: Stream[Int] = 2 #:: Stream.from(3).filter(i =>
ps.takeWhile(j => j * j <= i).forall(i % _ > 0))
val r = ps(10000)
println(r)
}
hereps
is of type collection Stream which is a variable actually but how its possible to call it like this ps(10000)
as its not any method and I also have one more expression val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _)
, here also I'm a little ambiguous about how we are calling fs.scanLeft(1)(_+_)
in the variable itself.Someone help!!
Upvotes: 2
Views: 591
Reputation: 2226
For the second part of the question,
lazy val fs:Stream[Int] = 0 #:: fs.scanLeft(1)(_ + _)
The #:: is cons operator Stream.cons used for constructing streams. The parameter of ConsWrapper is a by-name parameter and hence it is evaluated lazily.
It is therefore valid to reference fs after the #:: operator. I think we have to change the val to lazy val, otherwise the scala compiler throws forward reference extends over definition of value fs.
Upvotes: 1
Reputation: 149518
here
ps
is of type collection Stream which is a variable actually but how its possible to call it like this ps(10000) as its not any method
It's possible to call ps(10000)
because Stream
has an apply
method (Inherited from LinerSeqOptimized
):
/** Selects an element by its index in the $coll.
* Note: the execution of `apply` may take time proportial to the index value.
* @throws `IndexOutOfBoundsException` if `idx` does not satisfy `0 <= idx < length`.
*/
def apply(n: Int): A = {
val rest = drop(n)
if (n < 0 || rest.isEmpty) throw new IndexOutOfBoundsException("" + n)
rest.head
}
Calling ()
on any object in Scala will have the compiler looking for an apply
method on the object. This is similar to how you can instantiate case classes without the new
keyword, as the compiler generates apply
and unapply
automatically for you.
If we'll look at a simpler reproduce:
def main(args: Array[String]): Unit = {
val ps: Stream[Int] = Stream.from(1, 1)
val r = ps(1)
println(r)
}
The compiler is actually doing:
val r = ps.apply(1)
Where apply
for a collection usually looks up the element at index i
:
scala> val ps: Stream[Int] = Stream.from(1, 1)
ps: Stream[Int] = Stream(1, ?)
scala> val r = ps(1)
r: Int = 2
scala> val x = ps.apply(1)
x: Int = 2
If you actually want to see what the compiler generates:
object Problem7 extends Object {
def main(args: Array[String]): Unit = {
val ps: scala.collection.immutable.Stream = scala.`package`.Stream().from(1, 1);
val r: Int = scala.Int.unbox(ps.apply(1));
scala.this.Predef.println(scala.Int.box(r))
};
def <init>(): Problem7.type = {
Problem7.super.<init>();
()
}
}
}
Upvotes: 3