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)
}
Related
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: _*))
}
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.
def foldLeft[A, B] (as: List[A], z: B) (f: (B, A) => B) : B = as match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}
def reverse[A] (as: List[A]): List[A] =
foldLeft(as, List[A]())((h, acc) => Cons(acc, h))
I am not sure how List[A] in foldLeft is of type B. Can anyone clear the process happening in this functions?
This reverse implementation is calling foldLeft with A as it's first type argument (foldLeft#A = A) and List[A] as it's second type argument (foldLeft#B = List[A]). Here is a type annotated version that makes this very explicit:
def reverse[A] (as: List[A]): List[A] =
foldLeft[A, List[A]](as = as: List[A], z = List[A]())(
(h: List[A], acc: A) => Cons(acc, h): List[A]
)
Also Cons (if it is a Cons from standard library) creates a stream instead of list. Probably You want to use :: instead:
def reverse[A] (as: List[A]): List[A] =
foldLeft(as, List[A]())((acc, h) => h :: acc)
Can anyone tell me if something in the line with the following syntax is possible in Scala?
#annotation.tailrec
def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = {
def go(es: List[A], rs: Either[E, List[B]]): Either[E, List[B]] = {
es match {
case Nil => rs
case x::xs => for {
Right(b) <- f(x);
Right(ls) <- rs
} yield go(xs, Right(b::ls))
}
}
go(es, Right(List()))
}
I keep getting the following syntax exception
Error:(47, 12) constructor cannot be instantiated to expected type;
found : A$A400.this.Right[A]
required: List[?B3] where type ?B3 <: B (this is a GADT skolem)
Right(ls) <- rs
^
To be honest, I'm not entirely sure what the aim of the function is, but, guessing at what f is, here's something that may do what you want?
#annotation.tailrec
def f[A, B, E](e: A): Either[E, B] = ???
def go[A, B, E](es: List[A], rs: Either[E, List[B]]): Either[E, List[B]] = {
es match {
case Nil => rs
case x :: xs => (f(x), rs) match {
case (Right(b), Right(ls)) => go(xs, Right(b :: ls))
}
}
go(es, Right(List()))
}
I need to implement my own List class in Scala. I've implemented:
trait List[+A] {
/** The first element */
def head: A
/** The rest of the elements */
def tail: List[A]
def map[B](f: A => B): List[B]
def flatMap[B](f: A => List[B]): List[B]
def filter(f: A => Boolean): List[A]
// Concatenate two lists
def concat[B >: A](that: List[B]): List[B] = this match {
case Empty => that
case NonEmpty(head, tail) => NonEmpty(head, tail concat that)
}
}
/** The empty list, also known as Nil */
case object Empty extends List[Nothing] {
def head = throw new UnsupportedOperationException("Empty.head")
def tail = throw new UnsupportedOperationException("Empty.tail")
def map[B](f: Nothing => B): List[B] = Empty
def flatMap[B](f: Nothing => List[B]): List[B] = Empty
def filter(f: Nothing => Boolean): List[Nothing] = Empty
override def toString = "Empty"
}
And now I need to implement filter, flatMap and Map methods:
case class NonEmpty[A](head: A, tail: List[A]) extends List[A] {
//def map[B](f: A => B): List[B] = ???
//def flatMap[B](f: A => List[B]): List[B] = ???
def filter(predicate: A => Boolean): List[A] = {
}
For instance method filter(predicate: A => Boolean): List[A] how can I iterate through every element in this list? How can I check if given predicate is true or false? (tried if(predicate(head)) - doesn't work for some reason.)
Thank you for help.
You need to traverse the elements with head and tail:
def filter(f: A => Boolean): List[A] = {
def loop(xs: List[A], ys: List[A]): List[A] =
if (xs == Empty) ys else loop(xs.tail, if (f(xs.head)) NonEmpty(xs.head, ys) else ys)
loop(this, Empty).reverse
}
This implementation can be defined in List. The last thing you need for this is the reverse method. You can implement it the same way as filter - use an inner method to traverse all elements.
Instead of reverse you can use a non-tail-recursive implementation, which must not reversed and can be implemented in the subclasses:
def filter(f: A => Boolean): List[A] =
if (f(head)) NonEmpty(head, tail filter f)
else tail filter f
The other methods can be defined in a similar way.
Often, recursion gets easier when you just live in Fairyland and pretend (almost) everything already works.
Suppose filter already did what you asked, how would you use filter to make it work for yet another element?
Well, you can decide whether you want to to include the first element of your list (depending on f), and let filter, "which already works", handle the rest. Then just concatenate the list.
def filter(f: A => Boolean) : List[A] = {
if (f(head)) NonEmpty(head, tail.filter(f))
else tail.filter(f)
}