I am trying to write a scala function to reverse a list. However, IDEA is highlighting the (warning) line saying "fruitless type test: a value of type ListDefinition.List[T] cannot also be a::[B]"
object ListDefinition {
def reverseList[T](list: List[T]) : List[T] = list match {
(warning) case x :: EmptyList => // something
case _ => // do somehting
}
abstract class List[+T]
case object EmptyList extends List[Nothing]
case class ConsList[T](value: T, next: List[T]) extends List[T]
The case statement needs to use the Cons constructor for your list:
case ConsList(x, EmptyList) => // something
The :: constructor is for Scala lists and will not work for yours.
Related
I'm trying to execute this piece of code inside a Scala Worksheet (using Intellij):
Scala version I'm using is 2.11.12
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
def tail[A](l: List[A]): List[A] =
l match {
case Nil => sys.error("tail of empty list")
case Cons(_, t) => t
}
val a = List(1,2,3)
tail(a) //should be List(2,3)
The compiler gives me a 'Type mismatch, expected: List[NotInferedA], actual: List[Int].
Can someone help me?
Thanks
Your List class is missing a companion object. Calling List(1,2,3) constructs a default Scala List, not your list.
You need to add something like this (replace ??? with the real constructor functionality, probably using some recursive function):
object List {
def apply[A](s: A*) = ???
}
I am reading Functional Programming in Scala from Manning, authored by Paul Chiusano and Runar Bjarnason. In its 3rd chapter, there is a code to create a List and there are assignments to implement various methods of the list. Following is partial implementation of the my List
package src.Cons
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]
object List {
//my issue is I do not want to pass a list to sum but want to use objectName.sum notation
def sum(ints:List[Int]):Int = ints match {
case Nil => 0
case Cons(x,xs) => x+sum(xs)
}
}
Question - How can I create my list such that I can call l.sum instead of List.sum(l)?
You can "PmL", as #Gabriele Petronella has suggested, or you can move the sum() method to the Cons class, as #DeadNight wrote, but before either of those can work you have to resolve the current conflict between your List object and your List trait.
The sum() in your List object can only sum a List[Int] but your class definitions use a more generic type member and, as such, you can't use + because the compiler doesn't know how to add two A types.
If you want to restrict your List to only handling numeric types then this will work.
case class Cons[A: Numeric](h:A, t:List[A]) extends List[A] {
def sum: A = List.sum(this)
}
object List {
def sum[A](ints:List[A])(implicit ev: Numeric[A]):A = ints match {
case Nil => ev.zero
case Cons(x,xs) => ev.plus(x, sum(xs))
}
}
val x = Cons(4, Cons(2, Nil))
x.sum // res0: Int = 6
Making sum a member
The problem is, you don't know how to sum the List[A] for every type A, only a List[Int]. If there was a way to allow calls when A is an Int...
Let's take a look at the standard library for that. We're interested in Option#flatten method because:
val o1 = Option(Option(3)).flatten // compiles
val o2 = Option(4).flatten // does not compile
Notice the weird implicit ev: <:<[A, Option[B]]. This is the key here - it's a thing that compiler provides for you, but only if it is known at compile time, that your Option[A] is a subtype of Option[Option[B]] for some type B. This is the trick that we can use.
sealed trait List[+A] {
def sum(implicit ev: A <:< Int): Int = this match {
case Nil => 0
case Cons(x, xs) => x + xs.sum // <- here x is magically converted to Int, so we can use plus
}
}
case object Nil extends List[Nothing]
case class Cons[+A](h:A, t:List[A]) extends List[A]
println(Cons(4, Cons(38, Nil)).sum) // 42
ScalaFiddle
Notice that you can write <:<[A, B] as A <:< B.
NB: there's also =:=[A, B] type, for when your A is exactly Int - you can use either of those
Doing better?
Actually, std library has sum method and it's type is even weirder:
def sum(implicit ev: Numeric[A]). Doing so allows it to work on any number-like type like Double and Int, and has the operations for comparison, subtraction, multiplication, etc. So you can make it even more generic. I suggest you do it after reading a chapter about Monoids, tho :)
You can use the so-called "Pimp my Library" pattern.
Define an implicit class ListOps
implicit class ListOps[+A](list: List[A]) {
def sum = List.sum(this)
}
and now you can call list.sum. The implicit conversion will be triggered and the compiler will interpret it as ListOps(list).sum.
Move the definition of sum inside the definition of List trait
You can leave the concrete definitions to Nil & Cons
package src.Cons
sealed trait List[+A] {
def sum: Int
}
case object Nil extends List[Nothing] {
val sum: Int = 0
}
case class Cons[+A](h:A, t:List[A]) extends List[A] {
def sum: Int = h + t.sum
}
I want to implement a linked list in Scala where the type parameter is invariant, unlike the standard library List.
Here is an attempt:
sealed trait InvariantList[T]
case object Nil extends InvariantList[_]
case class Cons[T](head : T, tail : InvariantList[T]) extends InvariantList[T]
object InvariantList {
def map[A, B](xs : InvariantList[A])(f : A => B) : InvariantList[B] = {
xs match {
case Nil => Nil[B]
case Cons(head, tail) => Cons(f(head), map(tail)(f))
}
}
}
object Example {
val xs = Cons(7, Cons(5, Nil[Int]))
InvariantList.map(xs)(_ + 1)
}
This is pretty close to what I want, but it is annoying to have to specify the type parameter of Nil in the implementation of map and in the example use.
I also tried using case class Nil[T]() extends InvariantList[T], but this is also ugly because I have to put the parens all over the place.
What is the recommended way of defining Nil in an invariant linked list implementation? I think the question applies more generally to any invariant data structure that has cases with empty constructors. I would like it to be as convenient to use as the standard library List (convenient in that I don't have to specify the type parameter or add parens).
The standard library doesn't have a Nil element for its invariant collections. For example, Set and ListBuffer are invariant, but they do not have Nil sub-type. They require you to say Set.empty[A] or ListBuffer.empty[A].
scala> val l : ListBuffer[Int] = Nil
<console>:11: error: type mismatch;
found : scala.collection.immutable.Nil.type
required: scala.collection.mutable.ListBuffer[Int]
val l : ListBuffer[Int] = Nil
^
scala> val set: Set[Int] = Nil
<console>:11: error: type mismatch;
found : scala.collection.immutable.Nil.type
required: Set[Int]
val set: Set[Int] = Nil
^
Having a single case object Nil extends InvariantList[_] won't work because of invariance. Every list type would require it's own empty representation. Because an empty List[Dog] would not be the same as an empty List[Animal], if Dog <: Animal, etc.
What you're essentially asking for is a singleton symbol Nil to be treated like many different types. I think you're on the right track with a case class, because that will allow you one Nil[A] per list type. Unfortunately that will never allow you to pattern-match on Nil, only Nil(), because you need an extractor with parameters and not one for a singleton (which your Nil is not). If you want the convenience of not writing the type parameter and parentheses, you can write a method like this in the same package:
def nil[A] = Nil[A]()
It's not ideal, but it will partially solve your problem. Putting it all together:
sealed trait InvariantList[A]
case class Nil[A]() extends InvariantList[A]
case class Cons[A](head : A, tail : InvariantList[A]) extends InvariantList[A]
object InvariantList {
def map[A, B](xs : InvariantList[A])(f : A => B) : InvariantList[B] = {
xs match {
case Nil() => nil
case Cons(head, tail) => Cons(f(head), map(tail)(f))
}
}
}
scala> val xs = Cons(7, Cons(5, nil))
xs: Cons[Int] = Cons(7,Cons(5,Nil()))
scala> InvariantList.map(xs)(_ + 1)
res0: InvariantList[Int] = Cons(8,Cons(6,Nil()))
Below code causes compiler error :
Multiple markers at this line
- not found: type A
- not found: type A
at line def headOption :
object LazyList {
println("Welcome to the Scala worksheet")
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: _*))
def headOption : Option[A] = this match {
case Empty => None
case Cons(h, t) => Some(h())
}
}
}
But I think the function is defined correctly ? Since A is a generic type it should not cause this compiler error ?
You need to move def headOption into the Stream trait. Currently, it's in the Stream companion object. An object doesn't have a type parameter, because an object is just one determinate thing in memory, with a completely specific type. The Stream trait describes many possible Stream objects, each of which can have a different type, corresponding to the type filled in for A when the object is created.
Notice that you intend your this in headOption to refer to a specific Stream, not to the Stream companion object.
headOption should be defined as polymorphic function like what you did for empty and apply. So you need to add type annotation to your function as follow:
def headOption[A]: Option[A] = ...
However generally headOption should be moved to the trait and defining it in companion object is wrong. If you move it to the trait, the trait is typed so you do not need to add type annotation to the function and your current implementation will work.
Working more on FP in Scala examples, I tried to implement the Option trait's map function as follows:
sealed trait MyOption[+A] {
def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case _ => None
}
}
However, compile-time errors show, if I understand correctly, that I'm not pattern-matching correctly for the case of Some(A). Using pattern matching, how can I write the first case to get Some(A) values to match?
>scalac MyOption.scala
MyOption.scala:3: error: constructor cannot be instantiated to expected type;
found : Some[A(in class Some)]
required: MyOption[A(in trait MyOption)]
case Some(a) => Some(f(a))
^
MyOption.scala:3: error: not found: value a
case Some(a) => Some(f(a))
^
two errors found
You are trying to define map in terms of Some and None which are subclasses of the Scala-provided Option trait, rather than in terms of subclasses of your own trait. Try something like:
sealed trait MyOption[+A] {
import MyOption._
def map[B](f: A => B): MyOption[B] = this match {
case MySome(a) => MySome(f(a))
case _ => MyNone
}
}
object MyOption {
case class MySome[+A](a: A) extends MyOption[A]
case object MyNone extends MyOption[Nothing]
}