Avoiding type casting in pattern matching - scala

Given a hypothetical mutable linked list (let's assume this is a given structure -- so no suggestions about changing it, please):
trait CList[T]
trait CNil [T] extends CList[T]
trait CCons[T] extends CList[T] {
def head: T
def tail: CList[T]
}
And given Scala's type erasure, how can I iterate through it without casting:
#annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
case _: CNil [_] => None
case c: CCons[_] => lastValue(c.asInstanceOf[CCons[T]]) // ouch!
}
CList is invariant in T so there should be way to accomplish this?

You can try defining extractors:
object CNil {
def unapply[T](clist: CList[T]): Boolean = clist.isInstanceOf[CNil[_]]
}
object CCons {
def unapply[T](clist: CList[T]): Option[(T, CList[T])] = clist match {
case _: CNil[_] => None
case c: CCons[_] => Some(c.head, c.tail)
}
}
#annotation.tailrec def lastValue[T](l: CList[T]): Option[T] = l match {
case CNil() => None
case CCons(head, tail) => lastValue(tail)
}
You may have to give them another name if you can't put them in the same files as where the original traits are defined.
On another point, the implementation of your lastValue function probably doesn't do what you expect… How about this one instead?
def lastValue[T](clist: CList[T]): Option[T] = {
#annotation.tailrec
def lastValue0(prevValue: Option[T], clist: CList[T]): Option[T] =
clist match {
case CNil() => prevValue
case CCons(head, tail) => lastValue0(Some(head), tail)
}
lastValue0(None, clist)
}

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

When using HList with GADTs I am having to cast using asInstanceOf[H]. Is there a way to avoid the cast?

Given 2 GADT Algebras which know about each other and 2 interpreters that are mutually recursive, I am having issues having to cast from type A to type h <: HList even though in the context of the pattern match, it should be implied that type A is type h.
Is there a way to avoid the asInstanceOf[h] call in the interpreter?
abstract class KvpHList[H<:HList]
object KvpNil extends KvpHList[HNil]
case class KvpCons[H <: A :: T,A, T<:HList](head: KvpValue[A], tail: KvpHList[T])(implicit isHCons: IsHCons.Aux[H,A,T]) extends KvpHList[H] {
val hCons: IsHCons.Aux[H,A,T] = isHCons
}
abstract class KvpValue[A]
case object StringData extends KvpValue[String]
case class HListData[H <:HList](member: KvpHList[H]) extends KvpValue[H]
def hListInterpreter[H<:HList](hList: KvpHList[H]): H => String = {
hList match {
case KvpNil => (hNil: H) => "Nil"
case cons: KvpCons[H,a,t]=> {
implicit val hCons = cons.hCons
(input: H) => {
s"${kvpInterpreter(cons.head)(input.head)} :: ${hListInterpreter(cons.tail)(input.tail)}"
}
}
}
}
def kvpInterpreter[A](kvpValue: KvpValue[A]): A => String = {
kvpValue match {
case StringData => (str: String) => str
case h: HListData[h] => {
(input: A) => { // tried (input: h) as well
val toString: h => String = hListInterpreter(h.member)
toString(input.asInstanceOf[h]) // <--- CASTING :(
}
}
}
}
kvpInterpreter(HListData(KvpCons(StringData, KvpNil))).apply("Hello" :: HNil)
Since H in KvpCons is uniquely determined by A and T, KvpCons can be parametrized with two type parameters rather than three.
Type-level pattern matching is type classes
abstract class KvpHList[H <: HList]
object KvpNil extends KvpHList[HNil]
case class KvpCons[A, T <: HList](head: KvpValue[A], tail: KvpHList[T]) extends KvpHList[A :: T]
abstract class KvpValue[A]
case object StringData extends KvpValue[String]
case class HListData[H <: HList](member: KvpHList[H]) extends KvpValue[H]
trait HListInterpreter[H <: HList] {
def apply(hList: KvpHList[H]): H => String
}
object HListInterpreter {
implicit val nil: HListInterpreter[HNil] = new HListInterpreter[HNil] {
override def apply(hList: KvpHList[HNil]): HNil => String = _ => "Nil"
}
implicit def cons[A, T <: HList](implicit
headKvpInterpreter: KvpInterpreter[A],
tailHListInterpreter: HListInterpreter[T]
): HListInterpreter[A :: T] = new HListInterpreter[A :: T] {
override def apply(hList: KvpHList[A :: T]): A :: T => String = hList match {
case cons: KvpCons[_, _] => input => s"${headKvpInterpreter(cons.head)(input.head)} :: ${tailHListInterpreter(cons.tail)(input.tail)}"
}
}
}
def hListInterpreter[H <: HList](hList: KvpHList[H])(implicit hListInterp: HListInterpreter[H]): H => String = hListInterp(hList)
trait KvpInterpreter[A] {
def apply(kvpValue: KvpValue[A]): A => String
}
object KvpInterpreter {
implicit val string: KvpInterpreter[String] = new KvpInterpreter[String] {
override def apply(kvpValue: KvpValue[String]): String => String = str => str
}
implicit def hList[H <: HList : HListInterpreter]: KvpInterpreter[H] = new KvpInterpreter[H] {
override def apply(kvpValue: KvpValue[H]): H => String = kvpValue match {
case h: HListData[H] => input => {
val toString: H => String = hListInterpreter(h.member)
toString(input)
}
}
}
}
def kvpInterpreter[A](kvpValue: KvpValue[A])(a: A)(implicit kvpInterp: KvpInterpreter[A]): String = kvpInterp(kvpValue)(a)

scala variant type causes error type mismatch error

B is a super class of A , then as per scala variants and covariants . variant type can occur at parameter and covariant type can occur at function return type
My scala class make method is taking B type in paramters and returning subtype A as function type but as per function "make" it is correct but if i have companion class like case class for same class which is generic in A is giving error. I spent enough time to correct this error but not able to do so.
sealed class myList[+A] {
def apply[A](as: A*): myList[A] ={
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
def head():A = this.head
def tail():myList[A] = this.tail
def isEmpty():Boolean ={
this match {
case Nil => true
case _: myList[A] => false
}
}
def preappend[B>:A](x: B): myList[A] ={
if (isEmpty) make(x)
else make(x)
}
def append[B>:A](x: B): myList[A] ={
if (this.isEmpty) make(x)
else Cons(this.head,this.tail.append(x))
}
def print()={
this.map(println)
}
def make[B>:A](x:B): myList[A] ={
this match {
case Nil => Cons(x,Nil)
case Cons(xh, xs) => Cons(xh, xs.make(x))
}
}
def map[A,B](f: (A) => B): myList[B] = {
this match {
case Nil => Nil
case Cons(xh:A, xs:myList[A]) => Cons(f(xh),xs.map(f ))
}
}
/**
* Combines all elements of this list into value.
*
* Time - O(n)
* Space - O(n)
*/
def fold[B](n: B)(op: (B, A) => B): B = {
def loop(l: myList[A], a: B): B =
if (l.isEmpty) a
else loop(l.tail, op(a, l.head))
loop(this, n)
}
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
def foldRight[B,A](z: B)(f: (A, B) => B): B = this match {
case nil=> z
case Cons(x:A,xs:myList[A])=>f(x, foldRight(z)(f))
}
def length[B>:A](lst:myList[B]):Int={
this.foldRight(0) {( lst:myList[A],x:Int) => lst match{
case nil=>x
case _: myList[B] => x+1
}
}
}
def fail(m: String) = throw new NoSuchElementException(m)
}
case object Nil extends myList[Nothing] {
override def head: Nothing = fail("An empty list.")
override def tail: myList[Nothing] = fail("An empty list.")
override def isEmpty: Boolean = true
}
case class Cons[-A](head: A, tail: myList[A]) extends myList[A] {
override def isEmpty: Boolean = false
}
case class truck(
numberPlate:String
)
object Main {
def main(args: Array[String]) {
val a= new truck("1233bsd")
val b = new truck("dsads334")
val c = new myList[truck]
c.append(a)
c.print()
c.append(b)
c.print()
}
}
error i am getting:-
mylist-v2.scala:40: error: type mismatch;
found : x.type (with underlying type B)
required: A
case Nil => Cons(x,Nil)
^
mylist-v2.scala:50: warning: abstract type pattern A is unchecked since it is eliminated by erasure
case Cons(xh:A, xs:myList[A]) => Cons(f(xh),xs.map(f ))
^
mylist-v2.scala:50: warning: abstract type A in type pattern myList[A] is unchecked since it is eliminated by erasure
case Cons(xh:A, xs:myList[A]) => Cons(f(xh),xs.map(f ))
^
mylist-v2.scala:79: warning: abstract type pattern A is unchecked since it is eliminated by erasure
case Cons(x:A,xs:myList[A])=>f(x, foldRight(z)(f))
^
mylist-v2.scala:79: warning: abstract type A in type pattern myList[A] is unchecked since it is eliminated by erasure
case Cons(x:A,xs:myList[A])=>f(x, foldRight(z)(f))
^
four warnings found
one error found
I think the minimal changes to make this code compile is to change Cons to
case class Cons[+A](override val head: A, override val tail: myList[A]) extends myList[A] {
and signatures of prepend, append and make to
def preappend[B>:A](x: B): myList[B] ={
def append[B>:A](x: B): myList[B] ={
def make[B>:A](x:B): myList[B] ={
As you didn't describe your actual goal, it is hard to say whether this is what you really want or not.

#tailrec error "recursive call targetting a supertype"

Applying #tailrec I'm getting error from scala compiler: "could not optimize #tailrec annotated method get: it contains a recursive call targetting a supertype case _ => tail.get(n-1)". Could someone explain why is that?
trait List[T] {
def isEmpty: Boolean
def head: T
def tail: List[T]
def get(n: Int): T
}
class Cons[T](val head: T, val tail: List[T]) extends List[T]{
def isEmpty = false
#tailrec
final def get(n: Int) =
n match {
case 0 => head
case _ => tail.get(n-1)
}
}
class Nil[T] extends List[T]{
def isEmpty = true
def head = throw new NoSuchElementException("Nil.head")
def tail = throw new NoSuchElementException("Nil.tail")
final def get(n: Int): T = throw new IndexOutOfBoundsException
}
object Main extends App{
println(new Cons(4, new Cons(7, new Cons(13, new Nil))).get(3))
}
Try to imagine what's happening here and what you're asking the compiler to do. Tail call optimization, roughly, turns the method call into a loop, taking the arguments of the method and turning them into variables that are reassigned at each iteration of the loop.
Here, there are two such “loop variables”: n and the list cell itself on which the get method is called, which is actually this in the method body. The next value for n is fine: it's n - 1 and also an Int. The next value for the list cell, which is tail, is a problem, however: this has type Cons[T], but tail only has type List[T].
Thus, there is no way the compiler can turn it into a loop, as there is no guarantee that tail is a Cons[T] — and sure enough, at the end of the list, it is a Nil.
One way to “fix” it would be:
case class Cons[T](val head: T, val tail: List[T]) extends List[T] {
def isEmpty = false
#tailrec
final def get(n: Int) =
n match {
case 0 => head
case _ => tail match {
case c # Cons(_, _) => c.get(n - 1)
case nil # Nil() => nil.get(n - 1)
}
}
}
(Works if both Cons and Nil are case classes — but you'll probably want to make Nil a case object and List[T] covariant in T.)
In Cons.get you call tail.get as your tail call. But tail is of type List[T], not Cons[T]. So that call won't necessarily be handled by Cons.get, and Scala can't apply the tail recursion optimisation; the optimisation would turn the method call into a local jump back to the start of Cons.get, but that's not necessarily where the call is going.
Ben and Jean-Phillipe Pellet have already explained why the compiler complains. As for how to fix it, there is a straightforward solution: move the implementation of get right into List:
trait List[T] {
def isEmpty: Boolean
def head: T
def tail: List[T]
#tailrec
final def get(n: Int): T = {
n match {
case 0 => head
case _ => tail.get(n-1)
}
}
}
class Cons[T](val head: T, val tail: List[T]) extends List[T]{
def isEmpty = false
}
class Nil[T] extends List[T]{
def isEmpty = true
def head = throw new NoSuchElementException("Nil.head")
def tail = throw new NoSuchElementException("Nil.tail")
}

How do I use pattern matching with parametrized traits?

I have trouble with Scala traits and type erasure. I have this trait:
trait Meta[T] {
def ~=(e: T): Boolean
}
Now I want to use pattern matching to check for this case:
(m,i) match {
case (x:Meta[T], y: T) if x ~= y => println ("right")
case _ => println ("wrong")}
The T from x: Meta[T] should be the type of y or y should be a subtype of T.
If the types don't match I get an ClassCastException. But x ~= y should not be executed if the types are not correct. Is there a away around this or do I have to catch the exception and handle it that way?
I made an running example as short as possible:
trait Meta[T] {
type t = T
def ~=(e: T): Boolean
}
sealed abstract class A
case class Ide(s: String) extends A
case class MIde(s: String) extends A with Meta[A] {
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
sealed abstract class B
case class Foo(s: String) extends B
object Test {
def m = MIde("x")
def i = Ide("i")
def f = Foo("f")
def main[T](args: Array[String]) {
(m, i) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
// -> right
(m, f) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
// -> Exception in thread "main" java.lang.ClassCastException:
// Examples.Foo cannot be cast to Examples.A
}
}
UPDATE: added alternative at the end.
You are experiencing the limitations of pattern matching when it comes to generic types, due to type erasure.
All is not lost however. We can rely on ClassManifests to implement a generic method to convert your classes to a target type T (and another similar on to convert to Meta[T]):
trait Meta[T] { this: T =>
type t = T
def metaManifest: ClassManifest[T]
def ~=(e: T): Boolean
}
abstract sealed class Base {
def as[T:ClassManifest]: Option[T] = {
if ( classManifest[T].erasure.isAssignableFrom( this.getClass ) ) Some( this.asInstanceOf[T] )
else None
}
def asMeta[T:ClassManifest]: Option[T with Meta[T]] = {
this match {
case meta: Meta[_] if classManifest[T] <:< meta.metaManifest => as[T].asInstanceOf[Option[T with Meta[T]]]
case _ => None
}
}
}
abstract sealed class A extends Base
case class Ide(s: String) extends A
case class MIde(s: String) extends A with Meta[A] {
val metaManifest = classManifest[A]
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
sealed abstract class B extends Base
case class Foo(s: String) extends B
Let's test this in the REPL:
scala> m.as[A]
res17: Option[A] = Some(MIde(x))
scala> m.asMeta[A]
res18: Option[A with Meta[A]] = Some(MIde(x))
scala> i.as[A]
res19: Option[A] = Some(Ide(i))
scala> i.asMeta[A]
res20: Option[A with Meta[A]] = None
scala> f.as[A]
res21: Option[A] = None
scala> f.asMeta[A]
res22: Option[A with Meta[A]] = None
Sounds good. Now we can rewrite our pattern matching from this:
(m, i) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
to this:
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
So your example would now look like this:
object Test {
val m = MIde("x")
val i = Ide("i")
val f = Foo("f")
def test[T:ClassManifest]() {
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
// -> right
(m.asMeta[T], f.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
}
}
UPDATE: if setting explictly metaManifest everytime you mix Meta is not an option, you can let scala automtically infer it by passing it implictly in Metas constructor. This means that Meta must now be a class, and as a consequence A and B (and all similar types that must appear as Meta's type parameter) must now be traits, as you can't mix 2 classes. So you are basically swapping a restriction for another one. Choose your favorite one.
Here we go:
abstract sealed class Meta[T]( implicit val metaManifest: ClassManifest[T] ) { this: T =>
type t = T
def ~=(e: T): Boolean
}
trait Base {
def as[T:ClassManifest]: Option[T] = {
if ( classManifest[T].erasure.isAssignableFrom( this.getClass ) ) Some( this.asInstanceOf[T] )
else None
}
def asMeta[T:ClassManifest]: Option[T with Meta[T]] = {
this match {
case meta: Meta[_] if classManifest[T] != ClassManifest.Nothing && classManifest[T] <:< meta.metaManifest => as[T].asInstanceOf[Option[T with Meta[T]]]
case _ => None
}
}
}
trait A extends Base
case class Ide(s: String) extends A
case class MIde(s: String) extends Meta[A] with A {
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
trait B extends Base
case class Foo(s: String) extends B
object Test {
val m = MIde("x")
val i = Ide("i")
val f = Foo("f")
def test[T:ClassManifest]() {
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
(m.asMeta[T], f.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
}
}
Finally, if neither solution suits you, you could try another one: instead of mixing Meta[T] with T, just wrap it. Meta[T] would then just be wrapper to T, and you could even add an implicit conversion from Meta[T] to its wrapped value, so that an instance of Meta[T] can effectively be used like an instance of T almost transparently.