一个存在量化的类型变量是否可以强制只有一种类型?

时间:2014-05-01 05:17:57

标签: scala existential-type

考虑以下代码

trait Foo[T] {
  def one: Foo[_ >: T]
  def two: T
  def three(x: T)
}

def test[T](f: Foo[T]) = {
  val b = f.one
  b.three(b.two)
}

方法测试无法键入check。它说:

 found   : (some other)_$1(in value b)
 required: _$1(in value b)
     val x = b.three(b.two)

如果我正确地解释了这一点,编译器认为方法测试中的b有一个看起来像这样的类型(不是合法的语法,但希望更清楚):

trait Foo {
   def two: X where ∃ X >: T
   def three(x: X where ∃ X >: T)
}

我所希望的是它会有这样的类型:

∃ X >: T such that trait Foo {
   def two: X
   def three(x: X)
}

意图是,虽然不知道精确类型X,但编译器知道它的相同未知类型由" 2"并期待"三"。这似乎与正常的通用量化泛型发生的情况不同。以下编译,但暴露了我想要隐藏的类型参数X,因为它将在Foo的实例之间变化:

trait Foo[T] {
  def one[X >: T]: Foo[X]
  def two: T
  def three(x: T)
}

def test[T, X >: T](f: Foo[T]) = {
  val b = f.one[X]
  b.three(b.two)
}

有没有办法在存储量化的仿制药中获得相同的行为,当它们进行通用量化时会得到它们?

2 个答案:

答案 0 :(得分:2)

def one: Foo[_ >: T]相当于

def one: Foo[U >: T] forSome {type U >: T}

这个代替了

def one: Foo[U forSome {type U >: T}]

但我不明白为什么这会有所作为。好像不应该对我说。 (耸肩)

答案 1 :(得分:2)

问题是编译器认为

b.two: _>:T
b.three(_>:T)

即。两个是T的超类型,三个需要T的超类型。但是T的超类型不一定与另一个超类型T兼容,如本例所示:

A >: B >: C
def get:A
def put(B)
put(get) // type mismatch

因此,如果我们拥有的所有信息都是T的超类型,那么我们就无法安全地做到这一点。 我们必须明确告诉编译器它们是T的超类型。

trait Foo[T] {
  type U <: T
  def one: Foo[U]
  def two: T
  def three(x: T)
}

然后在实现特征时设置U

val x = new Foo[Dog]{
  type U = Mammal
  ...

我希望这种方法优于存在类型,因为它具有更清晰的语法以及这是Scala的核心,并且不需要导入该功能。