Scala - Confused with lazy syntax - scala

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)

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: _*))
}

Trouble following how flatMap eliminates Nil elements

I'm working through the book Functional Programming in Scala, and at the end of the data structures chapter you are asked to implement the filter method in terms of flatMap. Here are the necessary functions and implementations:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
def append[A](l1: List[A], l2: List[A]): List[A] = {
foldRight(l1, l2)((elem, acc) => Cons(elem, acc))
}
def concat[A](ls: List[List[A]]): List[A] = {
foldLeft(ls, Nil: List[A])(append)
}
def map[A, B](l: List[A])(f: A => B): List[B] = {
foldRight(l, Nil: List[B])((elem, acc) => Cons(f(elem), acc))
}
def filter[A](l: List[A])(f: A => Boolean): List[A] = {
List.flatMap(l)(a => if (f(a)) List(a) else Nil)
}
def flatMap[A, B](l: List[A])(f: A => List[B]): List[B] = {
concat(map(l)(f))
}
def foldRight[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
l match {
case Nil => z
case Cons(h, t) => f(h, foldRight(t, z)(f))
}
}
def foldLeft[A, B](l: List[A], z: B)(f: (B, A) => B): B = {
l match {
case Nil => z
case Cons(h, t) => foldLeft(t, f(z, h))(f)
}
}
}
The actual function call is here:
val x = List(1, 2, 3, 4, 5)
List.filter(x)(_ < 3)
As far as I can follow, after the map step you will have a List that looks like this:
Cons(Cons(1, Nil), Cons(2, Nil), Cons(Nil, Nil)...
I'm having trouble seeing where elements that are Nil are filtered out from the final result.
They are not "filtered out". They simply disappear after you apply concat on the list of lists, because concatenation with an empty list does nothing.

Use Cons operator for a custom trait

I have a MyStream-trait:
trait MyStream[+A] {
def uncons: Option[(A, MyStream[A])]
def isEmpty: Boolean = uncons.isEmpty
}
object MyStream {
def empty[A]: MyStream[A] =
new MyStream[A] { def uncons = None }
def cons[A](hd: => A, tl: => MyStream[A]): MyStream[A] =
new MyStream[A] { lazy val uncons = Some((hd, tl)) }
def apply[A](as: A*): MyStream[A] = if (as.isEmpty) empty
else cons(as.head, apply(as.tail: _*))
}
How can I use the uncons operator for pattern matching like:
def takeWhile(f: A => Boolean): MyStream[A] = this match {
case uncons(h,t) if f(h()) => cons(h(), t() takeWhile f)
case _ => empty
}
I am very new to Scala so I need a little help here.
Thanks!
How about this:
trait MyStream[+A] {
def uncons: Option[(A, MyStream[A])]
def isEmpty: Boolean = uncons.isEmpty
def takeWhile(f: A => Boolean): MyStream[A] = this match {
case MyStream(h, t) if f(h) => MyStream.cons(h, t takeWhile f)
case _ => MyStream.empty
}
#tailrec
final def foldLeft[B](z: B)(op: (B, A) => B): B =
this match {
case MyStream(h, t) => t.foldLeft(op(z, h))(op)
case _ => z
}
override def toString = this.foldLeft("") { case (acc, x) => acc + x }
}
object MyStream {
def empty[A]: MyStream[A] =
new MyStream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => MyStream[A]): MyStream[A] =
new MyStream[A] {
lazy val uncons = Some((hd, tl))
}
def apply[A](as: A*): MyStream[A] =
if (as.isEmpty) empty
else cons(as.head, apply(as.tail: _*))
def unapply[A](stream: MyStream[A]) = stream.uncons
}
object TestMyStream extends App {
import MyStream._
val s = cons(1, cons(2, cons(3, empty)))
println("All: " + s)
println("Take < 3: " + s.takeWhile(_ < 3))
}
prints:
All: 123
Take < 3: 12

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.

Lazy evaluation unexpected behaviour

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)?