我正在使用这个程序
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
}
并收到错误
constructor cannot be instantiated to expected type;
found : Cons[T]
required: Foo[?T1] where type ?T1 <: T (this is a GADT skolem)
但是,如果我摆脱了T
参数,它就可以正常工作了?
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
}
这是因为Foo
和Cons
的协方差。如果你删除+
,一切都会编译。在协变情况下,当你将Foo[T]
类型的v
与模式匹配时Cons(a, b)
这个a
不一定是具有相同T
的Foo[T]
类型,a
可以是任何类型,Foo[T']
与T' >: T
(或Foo[Any]
),这与返回类型相矛盾。使用自定义unapply
您可以消除类型的这种不确定性。
我似乎可以通过提供自己的Cons.unapply
来解决这个问题。我不清楚为什么我需要写自己的。
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
}
}
}