Lazy evaluation unexpected behaviour - scala

I was doing the exercises on Streams in the book "Functional Programming in Scala" and was a little confused by some behaviour. We have a Stream trait defined as follows:
sealed trait Stream[+A] {
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: Stream[A] = Empty
def apply[A](as: A*): Stream[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
And then say I do the following:
def test(i: Int) = {println("i: " + i); i}
val stream = cons(test(1), cons(test(2), cons(test(3), empty)))
Now when I create the stream this way the call to test(1) actually gets evaluated. Can someone tell me why this one is evaluated and not test(2) and test(3)?

Related

Scala type mismatch, cannot resolve symbol A, Pattern type is incompatible with expected type

I'm working on writing the Stream class in Chapter 5 of Functional Programming in Scala, I know the solutions are online, but it's not helping me. I faced the same issue with the previous Chapter writing the List class.
I got so frustrated I actually COPY PASTED from the solution to my Scala worksheet and still the same issue.
I thought maybe it's because of the name (there's already a List and Stream), doesn't seem like a smart idea to name them like this, so I changed it, didn't help.
Maybe it's something to do with Intellij (I'm using IntelliJ IDEA), I'm doing the exercises on the Scala Worksheets. But I can't find anything about this issue in relation to IDEs.
Here is what I have so far:
sealed trait StreamRED[+A]
case object Empty extends StreamRED[Nothing]
case class Cons[+A](h: () => A, t: () => StreamRED[A]) extends StreamRED[A]
object StreamRED {
def cons[A](hd: => A, tl: => StreamRED[A]): StreamRED[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: StreamRED[A] = Empty
def apply[A](as: A*): StreamRED[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
def headOption: Option[A] = this match {
case Empty => None
case Cons(h,t) => Some(h())
}
def toList: List[A] = {
#annotation.tailrec
def go(s: StreamRED[A], acc: List[A]): List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
}
I get the following errors:
"Cannot resolve symbol A" on the A in Option[A] (in headOption method) and List[A] and StreamRED[A] (in toList)
"Type mismatch. Required: StreamRED[Any], Found: StreamRED.type" on the this in toList.
"Pattern type is incompatible with expected type, found: Empty.type, required: StreamRED.type" on the Empty in headOption.
New to Scala, new to IntelliJ, new to statically typed languages, new to FP. Any explanations and recommendations for good reading materials much appreciated.
The two functions toList and headOption cannot be defined in the companion object of StreamRED.
If you define them directly in the trait it works:
sealed trait StreamRED[+A] {
def headOption: Option[A] = this match {
case Empty => None
case Cons(h,t) => Some(h())
}
def toList: List[A] = {
#annotation.tailrec
def go(s: StreamRED[A], acc: List[A]): List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
}
case object Empty extends StreamRED[Nothing]
case class Cons[+A](h: () => A, t: () => StreamRED[A]) extends StreamRED[A]
object StreamRED {
def cons[A](hd: => A, tl: => StreamRED[A]): StreamRED[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: StreamRED[A] = Empty
def apply[A](as: A*): StreamRED[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
A word of warning: Pattern matching on this is feels to me like bad practice. You know exactly what this is. Implement the functions in Empty and Cons instead.
Do this instead:
sealed trait StreamRED[+A] {
def headOption: Option[A]
def toList: List[A]
}
case object Empty extends StreamRED[Nothing] {
def headOption: Option[Nothing] = None
def toList: List[Nothing] = List()
}
case class Cons[+A](h: () => A, t: () => StreamRED[A]) extends StreamRED[A] {
def headOption: Option[A] = Some(h())
def toList: List[A] = h() +: t().toList
}
object StreamRED {
def cons[A](hd: => A, tl: => StreamRED[A]): StreamRED[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: StreamRED[A] = Empty
def apply[A](as: A*): StreamRED[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}

How stream passes incremental?

I am trying to understand how Stream works and have following Stream implementation:
sealed trait Stream[+A] {
def toList: List[A] = {
#annotation.tailrec
def go(s: Stream[A], acc: List[A]): List[A] = s match {
case Cons(h, t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
def foldRight[B](z: => B)(f: (A, => B) => B): B =
this match {
case Cons(h, t) => f(h(), t().foldRight(z)(f))
case _ => z
}
def map[B](f: A => B): Stream[B] =
this.foldRight(Stream.empty[B])((x, y) => Stream.cons(f(x), y))
def filter(f: A => Boolean): Stream[A] =
this.foldRight(Stream.empty[A])((h, t) => if (f(h)) Stream.cons(h, t) else t)
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](hd: => A, t1: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = t1
Cons(() => head, () => tail)
}
def empty[A]: Stream[A] = Empty
def apply[A](as: A*): Stream[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
and the code that is using Stream:
Stream(1,2,3,4).map((x) => {
println(x)
x + 10
}).filter((x) => {
println(x)
x % 2 == 0
}).toList
as output I've got:
1
11
2
12
3
13
4
14
res4: List[Int] = List(12, 14)
As you can see on the output, there is no intermediate result, the source will be pass one for one, how is that possible?
I can not image, how does it work.
Let's take a look at what the methods you used do on Stream:
map and filter are both implemented with foldRight. To make it clearer, let's inline foldRight inside map (the same can be done with filter), using the referential transparency principle:
def map[B](f: A => B) = this match {
case Cons(h, t) => Stream.cons(f(h()), t().map(f))
case _ => Empty
}
Now, where in this code is f evaluated? Never, since Stream.cons parameters are call-by-name, so we only give the description for the new stream, not its values.
Once you are convinced of this fact, you can easily see that the same will apply for filter, so we can move forward to toList.
It will evaluate each element in the Stream, putting the values in a List that will be reversed at the end.
But evaluating an element of the Stream which has been filtered and mapped is precisely reading the description of the values, so the actual functions are evaluated here. Hence the console output in order: first the map function is called then the filter function, for each element, one at a time (since we are now on the lazily mapped and filtered Stream).

Have to specify the parametric type

I have a Stream trait, that contains following method:
sealed trait Stream[+A] {
def takeWhile2(f: A => Boolean): Stream[A] =
this.foldRight(Stream.empty[A])((x, y) => {
if (f(x)) Stream.cons(x, y) else Stream.empty
})
#annotation.tailrec
final def exists(p: A => Boolean): Boolean = this match {
case Cons(h, t) => p(h()) || t().exists(p)
case _ => false
}
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](hd: => A, t1: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = t1
Cons(() => head, () => tail)
}
def empty[A]: Stream[A] = Empty
def apply[A](as: A*): Stream[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
Take a look at takeWhile2 body, it calls foldRight function.
When I would pass Stream.empty instead of Stream.empty[A], I would get compiler error, why?
That's because foldRight infers its type parameter from its first parameter list (ie its zero element).
Since this first element is Stream.empty, the type inferred is Stream[Nothing], and so it expects the second parameter to be a (A, Stream[Nothing]) => Stream[Nothing], which is clearly not the case.
The same issue is true with any fold operator on collections, Option, ...
That's because you have casted (x,y) as Stream.empty[A] when f(x) is true but when f(x) is false it will return Stream.empty[Nothing] i.e. if you don't specify a dataType default of Nothing is used. So the Stream[A] (expected return type) doesn't match with returned value of Stream[Nothing]

scala forward reference extends over definition

case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
sealed trait Stream[+A] {
def toList: List[A] = {
val buf = new collection.mutable.ListBuffer[A]
def go(s: Stream[A]): List[A] = s match {
case Cons(h, t) =>
buf += h()
go(t())
case _ => buf.toList
}
go(this)
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = Stream.cons(hd, tl)
def empty = Stream.empty
def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z) match {
case Some((h,t)) => cons(h, unfold(t)(f))
case None => empty
}
def take(n: Int): Stream[A] = unfold((this, n)) {
case (Cons(h, t), 1) => Some((h(), (empty, 0)))
case (Cons(h, t), n) if n > 1 => Some((h(), (t(), n-1)))
case (Empty, 0) => None
}
}
object Stream {
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = Cons(() => hd, () => tl)
def empty[A]: Stream[A] = Empty
val ones: Stream[Int] = Stream.cons(1, ones)
}
object StreamTest {
def main(args: Array[String]) {
//why compile error: forward reference extends over definition of value ones
/*val ones: Stream[Int] = Stream.cons(1, ones)
println(ones.take(5).toList)*/
println(Stream.ones.take(5).toList)
}
}
why compile error?: forward reference extends over definition of value ones
in pair object 'Stream',
val ones: Stream[Int] = Stream.scons(1, ones) is ok
but in main method, it's not ok (but... same synthetics!)
Local vals are not members.
For your test code, do this:
object StreamTest extends App {
//def main(args: Array[String]) {
//why compile error: forward reference extends over definition of value ones
val ones: Stream[Int] = Stream.cons(1, ones)
println(ones.take(5).toList)
println(Stream.ones.take(5).toList)
//}
}
The restriction in blocks is worded in the spec here, where the other advice is to make it a lazy val in the block, which has the same effect.
The forward reference is in Cons[+A]...which is referenced in this line:
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = Cons(() => hd, () => tl)
Try to move
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
into the companion object.

Scala - Confused with lazy syntax

Hello I'm reading the book called "Functional Programming in Scala". Book had code like this
trait Stream[+A] {
def uncons: Option[(A, Stream[A])]
def isEmpty: Boolean = uncons.isEmpty
}
object Stream {
...
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] =
new Stream[A] {
lazy val uncons = Some((hd, tl))
}
...
it says that hd: => A syntax is making this a lazy val
But the code in the github repo had something like this
trait Stream[+A]{
def toList: List[A] = {
#annotation.tailrec
def go(s: Stream[A], acc: List[A]) : List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
}
case class Cons[+A](h: ()=>A, t: () => Stream[A]) extends Stream[A]
What is the difference between h: =>A and h: ()=>A.
Why is the second part of code has () after argument like go(t(), h(), :: acc)