简体   繁体   中英

Scala generic: type mismatch

In the purpose of learning, I would like to understand how "::" class is working.
So I decided to create my own but instead of calling it "::" I want to call it ":++:"

From List.scala source code, the University of Helsinki and Programming In Scala 2nd edition (Chapter 22) I should write:

abstract class List[+A] {
    def isEmpty: Boolean
    def head: A
    def tail: List[A]
}

final case class :++:[A](head: A, tail: List[A]) extends List[A] {
  override def isEmpty: Boolean = false
}


I can create "::" objects

new ::(1, List(2))

But I can't create my ":++:" objects:

new :++:(1, List(2))
<console>:12: error: type mismatch;
found   : List[Int]
required: List[?]
            new :++:(1, List(2))

Where is my mistake?

Annotating the :++: type parameter gives you a hint:

scala> new :++:[Int](1, List(2))
<console>:11: error: type mismatch;
 found   : scala.collection.immutable.scala.collection.immutable.List[Int]
 required: List(in object $iw)[Int]
              new :++:[Int](1, List(2))
                                   ^

The :++: constructor expects one of your custom List[A] instances, but you give it a normal Scala List(1) .

But you currently have no way to create an instance of your list (other than having a null tail). If you add an equivalent of Nil , then you are all good:

case object Empty extends List[Nothing] { 
  def head = ???
  def isEmpty = true
  def tail = ???
}

And then you can create a :++: :

scala> val a = new :++:[Int](1, Empty)
a: :++:[Int] = :++:(1,Empty)

scala> val b = new :++:(2, a)
b: :++:[Int] = :++:(2,:++:(1,Empty))

In addition to gourlaysama's answer which explains why your definition is shadowed by the built-in List , I'd like to drop a few hints.

  1. Per answer above, you should also add the Empty or CNil case object for the 'empty' list.
  2. If you check the sources again, you'll find 'cons' method in the built-in List , similar to one below:

sealed abstract class ConsList[+A] {
    (...)
    def :++:[B >: A](x : B) : ConsList[B] = new :++:(x, this)
}

It allows you to create the list using infix notation:

val b = 2 :++: 4 :++: 7 :++: CNil

And finally, you can create a companion object for easier list creation:

object ConsList {
  def apply[A](xs : A*) = {
    xs.foldRight(CNil : ConsList[A])((el, l) => el :++: l)
  }
}

Which means that you can now create val c = ConsList(2, 4, 7) which will be equivalent to b above, and also equivalent to :++:(2, :++:(4, :++:(7, CNil)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM