I've been playing with Dotty and tried to implement a simple List. This is how I've implemented it:
enum List[+A] {
case Cons(head :A, tail: List[A])
case Nil extends List[Nothing]
}
The issue I'm having is that this implementation fails to compile with Cannot rewrite recursive call: it is not in tail position:
#tailrec
def drop[A](n: Int, as: List[A]): List[A] =
(n,as) match
case (0, _) => as
case (_, Nil) => Nil
case (x, Cons(_, tail)) => drop(x-1, tail)
On a different file I tried the same implementation, with standard library's List, and it compiles:
#tailrec
def drop[A](n: Int, as: List[A]): List[A] =
(n,as) match
case (0, _) => as
case (_, Nil) => Nil
case (x, _ :: tail) => drop(x-1, tail)
Maybe I'm just tired and not seeing the obvious error, but maybe there's something else here? Any weirdness caused by that extends List[Nothing] I had to add to make the code compile?
Thanks!
EDIT:
My code that leads to the compilation error
In Dotty 0.25.0-bin-20200429-c5a76f0-NIGHTLY
import scala.annotation.tailrec
enum List[+A] {
case Cons(head :A, tail: List[A])
case Nil extends List[Nothing]
#tailrec
def drop[A](n: Int, as: List[A]): List[A] =
(n,as) match
case (0, _) => as
case (_, Nil) => Nil
case (x, Cons(_, tail)) => drop(x-1, tail)
}
produces
TailRec optimisation not applicable, method drop is neither private nor final so can be overridden
If you make drop final or private the code compiles.
Related
I understand (kind of) how pattern matching works in Scala,
Let's say I have two lists of the form:
sealed abstract class IntList
case class Empty() extends IntList // The empty list, often called Nils
case class Element(n: Int, tail: IntList) extends IntList // Element is usually called Cons
Let's say I want to create the function take(n, xs)
It should return the first n elements of xs.
I tried with normal pattern matching:
def take(n: Int, xs: IntList): IntList = xs match {
case n == 0 => Empty()
case xs : Empty => Empty()
case xs : Element => Element(xs.n, take(n-1, xs))
}
But then of course, n is not recognised, error: not found: value == case n == 0 => Empty()
How can I do this, it is probably simple but I am a beginner in Scala?
You have a typo in the first case where it should be
case _ if n == 0 => Empty()
and a bug in third case where you forgot to pass the tail
case xs: Element => Element(xs.n, take(n-1, xs.tail))
Try
sealed trait IntList
case object Empty extends IntList
case class Element(n: Int, tail: IntList) extends IntList
def take(n: Int, xs: IntList): IntList = xs match {
case _ if n == 0 => Empty
case Empty => Empty
case Element(n, tail) => Element(n, take(n-1, tail))
}
val list = Element(1, Element(2, Element(3, Empty)))
take(2, list) // res0: IntList = Element(1,Element(2,Empty))
Consider case object instead of case class Empty() when there is no data as per Differences between case object T and case class T() when defining ADT?
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: _*))
}
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)))
}
I have a list of elements, and want to group them by class and then process the results.
trait H
case class A(x: Int) extends H
case class B(x: Int) extends H
val x = List(A(1),B(2),B(3))
val y = x.groupBy(_.getClass)
y.map(_ match {case (A, alist) => println("found me some As")
case (B, blist) => println("not As")})
Unfortunately this produces errors like:
<console>:17: error: pattern type is incompatible with expected type;
found : A.type
required: Class[_ <: Product]
Note: if you intended to match against the class, try `case _: A`
y.map(_ match {case (A, alist) => println("found me some As")
That is, I can't seem to find the proper way to do case matching when the item being matched is a class not just an instance of one.
A partial solution is the following:
val z = y.map(_ match {case (atype, alist) => alist })
z.map(_ match {
case alist if alist.head.isInstanceOf[A] => alist
case blist => List()
})
But it feels like there should be a better way of doing this using the keys to the initial Map returned from groupBy.
A in case (A, alist) refers to the companion object of A, which has the type A.type. That's why you're getting that error message. If you want to match against the class meta data, you should refer to classOf[A]. There's also no reason to use match, as you can pattern match with map already.
y.map {
case (c, alist) if(c == classOf[A]) => println("found me some As")
case (c, blist) if(c == classOf[B]) => println("not As")
}
I am trying to do some examples programs in scala to get more familiar with the language, For that I am trying to re-implement some of the built in methods in Haskell, Most of these methods I am sure are also implemented in Scala too, But these are just for my practice. I think I can post some of code snippets (not all of them) to get a better way of doing things and to validate my understanding of scala. So please let me know if this is not the place to do these things.
Here is my scala implementation to get the last element of any list. Is this the right way of doing things, By using Any am I loosing the type of the object containing in the list? Is this how this kind of things implemented in scala?
def getLast(xs: List[Any]): Any = xs match {
case List() => null
case x :: List() => x
case _ :: ys => getLast(ys)
}
Parameterize the type of your function and use "Nil" instead of List() like so:
def getLast[T](xs: List[T]): T = xs match {
case Nil => null.asInstanceOf[T]
case x :: Nil => x
case _ :: ys => getLast(ys)
}
Also, consider making it return an Option type:
def getLast[T](xs: List[T]): Option[T] = xs match {
case Nil => None
case x :: Nil => Some(x)
case _ :: ys => getLast(ys)
}
Usage:
val listOfInts = List(1,2,3)
assert(getLast(listOfInts).isInstanceOf[Int])
val listOfStrings = List("one","two","three")
assert(getLast(listOfStrings).isInstanceOf[String])
Firstly, avoid the null, and especially null.asInstanceOf[T]. Observe the danger with primitives:
scala> null.asInstanceOf[Int]
res19: Int = 0
scala> null.asInstanceOf[Boolean]
res20: Boolean = false
So the signature should either be List[T] => T, whereby last on an empty iterator throws an exception:
def last[T](ts: List[T]): T = ts match {
case Nil => throw new NoSuchElementException
case t :: Nil => t
case t :: ts => last(ts)
}
Or instead: List[T] => Option[T]
def lastOption[T](ts: List[T]): Option[T] = ts match {
case Nil => None
case t :: Nil => Some(t)
case t :: ts => lastOption(ts)
}
def lastOption1[T](ts: List[T]): Option[T] = ts.reverse.headOption
def lastOptionInScala28[T](ts: List[T]): Option[T] = ts.lastOption // :)