我有一个简单的类来表示向量,因此不同长度的向量可以解析为不同的类型。但是,在实现zip方法时遇到一些困难。这是我所做工作的最小化版本,以及我觉得有点神秘的编译器消息。
sealed trait Vector[A] {
type ThisButType[B] <: Vector[B]
def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]]
}
case class Term[A]() extends Vector[A] {
type ThisButType[B] = Term[B]
def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]] = Term[Tuple2[A, B]]()
}
case class Component[A, T <: Vector[A]](value: A, tail: T) extends Vector[A]{
type ThisButType[B] = Component[B, T#ThisButType[B]]
def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]] =
Component[Tuple2[A,B], T#ThisButType[Tuple2[A, B]]]((value, other.value), tail.zip(other.tail))
}
我得到的错误是:
type mismatch;
found : other.tail.type (with underlying type T#ThisButType[B])
required: Component.this.tail.ThisButType[B]
在这种情况下,编译器为什么不能弄清楚T
应该和Component.this.tail
一样?
答案 0 :(得分:2)
假设确实如此:
// applying some other minor changes...
sealed trait Vector[A] {
type ThisButType[B] <: Vector[B]
def zip[B](other: ThisButType[B]): ThisButType[(A, B)]
}
case class Term[A]() extends Vector[A] {
override type ThisButType[B] = Term[B]
override def zip[B](other: Term[B]): Term[(A, B)] = Term()
}
case class Component[A, T <: Vector[A]](value: A, tail: T) extends Vector[A] {
override type ThisButType[B] = Component[B, T#ThisButType[B]]
override def zip[B](other: Component[B, T#ThisButType[B]]): Component[(A, B), T#ThisButType[(A, B)]] =
Component((value, other.value), tail.zip(other.tail.asInstanceOf[tail.ThisButType[B]]))
}
但是然后...
val zero = Term[Unit]()
val zero0: Vector[Unit]#ThisButType[Int] = Term[Int](): zero.ThisButType[Int] // the mystical double type ascription!
val two = Component((), Component((), Term[Unit]()): Vector[Unit])
two.zip(Component(0, zero0)) // ClassCastException!
因此,关于您的代码的某些错误实际上是类型错误的,编译器正确地将其视为错误。具体来说,代码中的T#ThisButType[B]
与tail.ThisButType[B]
完全不同 ,因为tail
不必是确切的类型T
但可以是某些子类型。在这种情况下,T#ThisButType[B]
可以包含tail.ThisButType[B]
不包含的值,这意味着您无法将前一个(other.tail
)传递给想要的函数(tail.zip
)后者。
故事的道德:类型投射是邪恶的,应该避免。您在那里拥有完美的 value tail: T
;只是从中投射。
// applying some more minor changes...
sealed trait Vector[+A] {
type ThisButType[+B] <: Vector[B]
def zip[B](other: ThisButType[B]): ThisButType[(A, B)]
}
case object Term extends Vector[Nothing] {
override type ThisButType[+B] = Term.type
override def zip[B](other: Term.type): Term.type = Term
}
case class Component[+A, +T <: Vector[A]](value: A, tail: T) extends Vector[A] {
override type ThisButType[+B] = Component[B, tail.ThisButType[B]]
override def zip[B](other: Component[B, tail.ThisButType[B]]): Component[(A, B), tail.ThisButType[(A, B)]] =
Component((value, other.value), tail.zip(other.tail))
}
之前的示例不再起作用:
val zero: Vector[Unit]#ThisButType[Int] = Term: Term.ThisButType[Int]
val two = Component((), Component((), Term): Vector[Unit])
two.zip(Component(0, zero)) // fails: don't know that zero: two.tail.ThisButType[Int]
现在代码正确了。