Can an existentially quantified type variable be forced to have only a single type?

╄→гoц情女王★ 提交于 2019-12-30 10:12:39

问题


Consider the following code

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)
}

The method test fails to type check. It says:

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

If I am interpreting this correctly, the compiler thinks that b in method test has a type that looks like this (not legal syntax, but hopefully clearer):

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

What I was hoping for was that it would have a type like this:

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

The intent being that while the precise type X is not known, the compiler knows that its the same unknown type being returned by "two" and expected by "three". This seems different from what happens with normal univerally quantified generics. The following compiles, but exposes the type parameter X which I want to hide as it will vary between instances of 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)
}

Is there a way to get the same behaviour for existentially quantified generics we get when they're univerally quanified?


回答1:


def one: Foo[_ >: T] is equivalent to

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

this one instead works

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

I do not however understand why this would make a difference. It seems like it should not to me. (shrug)




回答2:


The problem is the compiler thinks that

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

i.e. two is a supertype of T and three requires a supertype of T. But a supertype of T is not necessarily assignment compatible with another supertype of T, as in this example:

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

So if all the information we have is that they are supertypes of T then we cannot do this safely. We have to explicitly tell the compiler that they are the same supertype of T.

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

Then just set U when you implement the trait:

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

I would prefer this approach over the existential types due to the cleaner syntax and the fact that this is core Scala and does not need the feature to be imported.



来源:https://stackoverflow.com/questions/23402431/can-an-existentially-quantified-type-variable-be-forced-to-have-only-a-single-ty

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!