Reputation: 10415
I'm working with this program
abstract class Foo[+T[_]] {}
case object Unit extends Foo
case class Cons[+T[_]](a: Foo[T], b: Foo[T]) extends Foo[T]
case class Strings[T[_]](x: T[String]) extends Foo[T]
def first[T[_]](v: Foo[T]): Option[Foo[T]] = v match {
case Cons(a, b) => Some(a)
case _ => None
}
and getting the error
constructor cannot be instantiated to expected type;
found : Cons[T]
required: Foo[?T1] where type ?T1 <: T (this is a GADT skolem)
But if I get rid of the parameter for T
it works just fine?
abstract class Foo[+T] {}
case object Unit extends Foo
case class Cons[+T](a: Foo[T], b: Foo[T]) extends Foo[T]
case class Val[T](x: T) extends Foo[T]
def first[T](v: Foo[T]): Option[Foo[T]] = v match {
case Cons(a, b) => Some(a)
case _ => None
}
Upvotes: 2
Views: 107
Reputation: 51658
This is because of covariance of Foo
and Cons
. If you remove +
s everything will compile. In covariant case when you match v
of type Foo[T]
with pattern Cons(a, b)
this a
is not necessarily of type Foo[T]
with the same T
, a
can be of any type Foo[T']
with T' >: T
(or Foo[Any]
), which contradicts return type. With your custom unapply
you remove this uncertainty in type.
Upvotes: 2
Reputation: 10415
I seem to be able to solve this by supplying my own Cons.unapply
. I'm unclear why I need to write my own.
object Cons {
def unapply[T[_]](v: Foo[T]): Option[(Foo[T], Foo[T])] = {
if(v.isInstanceOf[Cons[T]]) {
v.asInstanceOf[Cons[T]] match {
case Cons(a,b) => Some((a,b))
case _ => None
}
} else {
None
}
}
}
Upvotes: 0