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.
Related
I had a problem coding a function called head, that basically replace the head elements with another for the List invoking it:
List(1,2,3,4).head(4) // List(4,2,3,4)
The code is obviously useless, I was just trying to have fun with Scala. This is the code:
sealed trait List[+A]{
def tail():List[A]
def head[A](x:A):List[A]
}
object Nil extends List[Nothing]{
def tail() = throw new Exception("Nil couldn't has tail")
def head[A](x:A): List[A] = List(x)
}
case class Cons[+A](x :A, xs: List[A]) extends List[A]{
def tail():List[A] = xs
def head[A](a:A): List[A] = Cons(a,xs)
}
object List{
def apply[A](as:A*):List[A] = {
if (as.isEmpty) Nil
else Cons(as.head,apply(as.tail: _*))
}
}
Cons(1,Cons(2,Nil)) == List(1,2)
Cons(1,Cons(2,Cons(3,Cons(4,Nil)))).tail()
List(1,2,3,4,5,6,7).tail()
List(1,2,3,4).head(4)
It doesn't not compile and I have this error:
Error:(11, 39) type mismatch;
found : A$A318.this.List[A(in class Cons)]
required: A$A318.this.List[A(in method head)]
def head[A](a:A): List[A] = Cons(a,xs)
Could you explain why, please?
Regards.
Your problem is that your head method is taking another type A, therefore inside that scope the compiler takes those As as different, i.e., the A defined in the trait is shadowed by the A in head[A].
Also, your head method is taking a covariant element of type A in a contravariant position, so you can't define head as such.
What you can do is defining your head as:
def head[B >: A](x: B): List[B]
Hence, you get:
object S {
sealed trait List[+A] {
def tail(): List[A]
def head[B >: A](x: B): List[B]
}
case object Nil extends List[Nothing] {
def tail() = throw new Exception("Nil doesn't have a tail")
def head[B >: Nothing](x: B): List[B] = Cons(x, Nil)
}
case class Cons[+A](x: A, xs: List[A]) extends List[A] {
def tail(): List[A] = xs
def head[B >: A](a: B): List[B] = Cons(a, xs)
}
object List {
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
}
}
Testing this on the REPL:
scala> :load test.scala
Loading test.scala...
defined object S
scala> import S._
import S._
scala> Nil.head(1)
res0: S.List[Int] = Cons(1,Nil)
scala> Cons(1, Nil).head(4)
res1: S.List[Int] = Cons(4,Nil)
You method head does not need a type parameter, since you already have one defined in the class definition and that is exactly the type you want head to receive (if you want head to create a list of the same type of the original).
The error you get is because A is two different types in the context of the method head (the one from the method and the other from the class).
The definition for head should be:
def head(x:A):List[A]
Summary: I want to add an instance method to instances of a parametrized type, but only for some values of the type parameter. Specifically, I have List[E], but I only want instances of List[List[_]] to have a flatten() method.
I am learning the basics of Scala and functional programming by following along with the exercises in Functional Programming in Scala by Chiusano & Bjarnason.
Suppose I have a type List[E] and a companion object List that has methods for working with instances of List[E].
sealed trait List[+E]
case object Nil extends List[Nothing]
case class Cons[+E](head: E, tail: List[E]) extends List[E]
object List {
def flatten[E](aListOfLists: List[List[E]]): List[E] = Nil
def foldLeft[E, F](aList: List[E])(acc: F)(f: (F, E) ⇒ F): F = acc
}
Now suppose I want to create analogous methods on List instances that simply forward the calls to the companion object. I would try to augment the trait definition as follows.
sealed trait List[+E] {
def foldLeft[F](acc: F)(f: (F, E) => F) = List.foldLeft(this)(acc)(f)
}
I run into a complication: List.foldLeft() works with any List[E], but List.flatten() expects a List[List[E]] argument. Thus, I only want instances of List[List[_]] to have this method. How can I add flatten() to the appropriate subset of List instances? How do I use Scala's type system to express this restriction?
We can build up what we need piece by piece. First we know that we need a type parameter for our flatten, since we don't otherwise have a way to refer to the inner element type:
sealed trait List[+E] {
def flatten[I] // ???
}
Next we need some way of establishing that our E is List[I]. We can't add constraints to E itself, since in many cases it won't be List[I] for any I, but we can require implicit evidence that this relationship must hold if we want to be able to call flatten:
sealed trait List[+E] {
def flatten[I](implicit ev: E <:< List[I]) = ???
}
Note that for reasons related to variance (and type inference) we need to use <:< instead of =:=.
Next we can add the return type, which we know must be List[I]:
sealed trait List[+E] {
def flatten[I](implicit ev: E <:< List[I]): List[I] = ???
}
Now we want to be able to call List.flatten on a List[List[I]]. Our ev allows us to convert values of type E into List[I], but we don't have E values, we just have a List[E]. There are a number of ways you could fix this, but I'll just go ahead and define a map method and use that:
sealed trait List[+E] {
def map[B](f: E => B): List[B] = this match {
case Nil => Nil
case Cons(h, t) => Cons(f(h), t.map(f))
}
def flatten[I](implicit ev: E <:< List[I]): List[I] = List.flatten(map(ev))
}
And then:
val l1 = Cons(1, Cons(2, Nil))
val l2 = Cons(3, Cons(4, Cons(5, Nil)))
val nested = Cons(l1, Cons(l2, Nil))
val flattened: List[Int] = nested.flatten
This won't actually work, since your List.flatten is broken, but it should when you fix it.
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.
The below code defines a List type and two implementation of case classes one representing empty list and Cons to create actual list
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: _*))
}
val example = Cons(1, Cons(2, Cons(3, Nil)))
}
is my assumption correct that the list is created by the recursive apply method above when the val example = ... is executed.
if that is so. the signature for creating Cons is Cons(head, tail) where as the signature of the apply is incompatible variad def apply[A](as: A*): List[A], how does scala actually infers the val example to be List(1, 2, 3, Nil)
When you say
class Foo(s: String, i: Int)
in scala, it generates a class Foo with a constructor taking a String and an Int.
It's pretty much the same as a java class declared as
public class Foo {
public Foo(String s, int i) {
...
}
}
With case classes, the compiler provides extra-goodies such as a companion object with a default apply method taking the same parameters as the constructor.
So that's why you can directly call Cons(head, tail), without explicitly define a constructor.
I know there are already some ways of making traversal generic in scala, but I'm trying to define a simple trait that encapsulates a traversable type. However, I'm having trouble getting the type signatures to work out. A first attempt would be something like the following:
trait Traversable1[B] {
def head: Option[B]
def next: Traversable1[B]
}
This works well, except I want next to return an object that has the same type as the original traversable, not the more generic traversable type. For example, if List has the trait Traversable1, it's next method should return something of type List, not Traversable1. Thus, my second attempt was the following:
trait Traversable2[A[B] <: Traversable2[A[B]] {
def head: Option[B]
def next: A[B]
}
Here, A could equal List, so next would return a List[B]. Unfortunately, this code does not compile: A[B] takes no type parameters, expected: one
How can I achieve what I'm trying to do?
You could create a trait like:
trait Traversable[T[_]] {
def head[A](t: T[A]): Option[A]
def next[A](t: T[A]): T[A]
}
then implement it for lists like:
implicit val listTraversable = new Traversable[List] {
def head[A](l: List[A]) = l match {
case Nil => None
case x::_ => Some(x)
}
def next[A](l: List[A]) = l.tail
}
You can then make use of it using the 'type class' pattern by taking an implicit implementation of the trait to do the work e.g.
def foreach[T[_], A](t: T[A], f: A => Unit)(implicit trav: Traversable[T]): Unit = {
trav.head(t) match {
case Some(v) =>
f(v)
foreach(trav.next(t), f)
case None => ()
}
}
and call it with
foreach(List(1,2,3), println)