Trouble following how flatMap eliminates Nil elements - scala

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.

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

Error Calling Generic Function In Scala

So I'm following fpinscala and I have this Object:
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 sum(ints: List[Int]): Int = ints match {
case Nil => 0
case Cons(x, xs) => x + sum(xs)
}
def product(ds: List[Double]): Double = ds match {
case Nil => 1
case Cons(x, xs) => x * product(xs)
}
def apply[A](as: A*): List[A] =
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
def tail[A](as: List[A]): List[A] = as match {
case Nil => as
case Cons(_, xs) => xs
}
def setHead[A](as: List[A], a: A): List[A] = as match {
case Nil => Cons(a, Nil)
case Cons(_, xs) => Cons(a, xs)
}
def main(args: Array[String]): Unit =
println(tail(List(1,2,3)))
}
When I try to run main I get:
error: type mismatch;
found : List[Int] (in scala.collection.immutable)
required: List[?] (in <empty>)
println(tail(List[Int](1,2,3)))
I have followed the book pretty exactly so I don't know what I'm missing here. It says you should now be able to call List(1, 2, 3, 4) or List("hello", "goodbye") with no issues. But I can't pass that to the function? Some insight on what I'm missing would be appreciated.
The code compiles correctly, the only problem I see is that you are declaring the main method in the List companion object and that is incorrect, you should move it to other object:
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 sum(ints: List[Int]): Int = ints match {
case Nil => 0
case Cons(x, xs) => x + sum(xs)
}
def product(ds: List[Double]): Double = ds match {
case Nil => 1
case Cons(x, xs) => x * product(xs)
}
def apply[A](as: A*): List[A] =
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
def tail[A](as: List[A]): List[A] = as match {
case Nil => as
case Cons(_, xs) => xs
}
def setHead[A](as: List[A], a: A): List[A] = as match {
case Nil => Cons(a, Nil)
case Cons(_, xs) => Cons(a, xs)
}
}
object Main {
def main(args: Array[String]): Unit =
println(List.tail(List(1,2,3)))
}

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

implicit resolution for a function argument

I tried to implement mergesort in Scala. I got to the following:
def mergeSort[A: Ordering](as: List[A]): List[A] = as match {
case Nil => as
case head :: Nil => as
case _ => {
val (l, r) = split(as)
merge(mergeSort(l), mergeSort(r))
}
}
def split[A](as: List[A]): (List[A], List[A]) = {
def rec(todo: List[A], done: (List[A], List[A])): (List[A], List[A]) = todo match {
case Nil => done
case head :: tail => rec(tail, (head :: done._2, done._1))
}
rec(as, (Nil, Nil))
}
def merge[A: Ordering](left: List[A], right: List[A]) = {
def rec(left: List[A], right: List[A], done: List[A]): List[A] =
(left, right) match {
case (_, Nil) => rprepend(left, done)
case (Nil, _) => rprepend(right, done)
case (lh :: lt, rh :: rt) => if (implicitly[Ordering[A]].compare(lh, rh) <= 0)
rec(lt, right, lh :: done)
else rec(left, rt, rh :: done)
}
rec(left, right, Nil).reverse
}
def rprepend[A](prepend: List[A], as: List[A]): List[A] =
prepend.foldLeft(as)((r, a) => a :: r)
This question is not about the obscene amount of inefficient reversing going on, nor about the lack of tail recursion. Rather, I noticed that you could generalize mergesort by passing in a sort algorithm like so:
def generalizedMergeSort[A: Ordering](as: List[A], sort: List[A] => List[A]): List[A] = as match {
case Nil => as
case head :: Nil => as
case _ => {
val (l, r) = split(as)
merge(sort(l), sort(r))
}
}
Then I tried re-implementing mergesort as
def mergesort[A: Ordering](as: List[A]): List[A] = {
generalizedMergeSort(as, mergesort)
}
but this fails to compile, not finding the proper Ordering[A]:
[error] test.scala:17: No implicit Ordering defined for A.
[error] generalizedMergeSort(as, mergesort)
[error] ^
as a feeble attempt to get things in scope I tried
def mergesort[A: Ordering](as: List[A]): List[A] = {
implicit val realythere = implicitly[Ordering[A]]
generalizedMergeSort(as, mergesort)
}
but to no avail.
I suspect the problem may be in the second parameter of generalizedMergesort. I say the parameter is a List[A] => List[A], but I pass in a List[A] => implicit Ordering[A] => List[A] but I don't know how to make use of that to get to my goal of implementing mergesort in terms of generalizedMergesort and itself.
You can overcome this by passing a function that calls mergesort to generalizedMergeSort. This call will capture the implicit Ordering:
def mergesort[A: Ordering](as: List[A]): List[A] = {
generalizedMergeSort(as, mergesort(_: List[A]))
}
mergesort(_: List[A]) is a closure function of type List[A] => List[A], which calls mergesort with its argument, and the implicit Ordering argument gets captured in this closure.
The simple solution is to extract implicit from method to upper method:
def mergesort[A: Ordering](as: List[A]): List[A] = {
def mergesort0(xs: List[A]): List[A] = generalizedMergeSort(xs, mergesort0)
mergesort0(as)
}
and second is to wrap your function with implicit (with additional object creation):
def mergesort[A: Ordering](as: List[A]): List[A] = {
val mergesort0: List[A] => List[A] = xs => mergesort(xs)
generalizedMergeSort(as, mergesort0)
}

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)