2013-08-23 4 views
8

Немного смущает о экзистенциальных типах.Экзистенциальные типы в Scala

Это работает для меня:

def valueOf(c: Class[_], name: String) { 
    type C = Class[T] forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[C], name) 
} 

, но это не делает:

def valueOf(c: Class[_], name: String) { 
    type T = T forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[Class[T]], name) 
} 

На мой взгляд, оба выражения эквивалентны:

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name) 

Но Scala говорит, что это в мой разум только:

inferred type arguments [T] do not conform to method valueOf's type parameter bounds [T <: Enum[T]] 
     Enum.valueOf(c.asInstanceOf[Class[T]], name) 
      ^

ответ

5

Рассмотрим разницу между следующими двумя выражениями:

Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name) 

И:

Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name) 

Теперь подумайте о том, как параметр типа T из valueOf будет выведено в каждом из этих случаев. В первом случае у нас есть X, который, как мы знаем, является подтипом Enum[X], и мы все настроены. Во втором случае, с другой стороны, T должно быть X forSome { type X <: Enum[X] }, и в решающем случае этот тип не является подтипом Enum[X forSome { type X <: Enum[X] }], поэтому мы не выполнили ограничение на T.

Проблема в том, что ваш второй пример эквивалентен последнему.


В сноске, это будет работать нормально, если Enum были ковариантны в параметре типа. Возьмем следующий упрощенный пример:

trait Foo[A] 
trait Bar[A] 

def foo[A <: Bar[A]](f: Foo[A]) = f 

def x: Foo[X] forSome { type X <: Bar[X] } = ??? 
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ??? 

Теперь foo(x) компилируется, но foo(y) не будет, так же, как в вашем коде. Но сменить Bar немного:

trait Foo[A] 
trait Bar[+A] 

def foo[A <: Bar[A]](f: Foo[A]) = f 

def x: Foo[X] forSome { type X <: Bar[X] } = ??? 
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ??? 

Теперь они оба скомпилируются. Я бы предположил, что это имеет какое-то отношение к причине того, что у нас есть такие сильные интуиции, что ваши два примера эквивалентны.


В качестве другой сноски (в ответ на gzmo «s comment below), необходимо учитывать следующее:

scala> trait Foo[A <: Foo[A]] 
defined trait Foo 

scala> class MyFoo extends Foo[MyFoo] 
defined class MyFoo 

scala> val myFoo = new MyFoo 
myFoo: MyFoo = [email protected] 

scala> myFoo: (X forSome { type X <: Foo[X] }) 
res0: X forSome { type X <: Foo[X] } = [email protected] 

scala> myFoo: Foo[MyFoo] 
res1: Foo[MyFoo] = [email protected] 

Давайте предположим, что X forSome { type X <: Foo[X] }были подтипом Foo[X forSome { type X <: Foo[X] }] (не обращая внимания на мгновение тот факт, что последний даже не является допустимым типом). Тогда мы смогли бы написать следующее:

myFoo: Foo[X forSome { type X <: Foo[X] }] 

Но Foo инвариантно, поэтому, если есть вещь, которая является экземпляром как Foo[A] и Foo[B], то это должно быть так, что A =:= B. Но это определенно не тот случай, когда MyFoo =:= (X forSome { type X <: Foo[X] }).Не уверен, что все это путано, но я убедился, что компилятор знает, что он здесь делает.

+0

Я не понимаю, почему 'X forSome {type X <: Enum [X]}' не является подтипом 'Enum [X forSome {type X <: Enum [X]}]' (на мой взгляд, 'X <: Enum [X] ', и те же ограничения применяются рекурсивно). Вы можете объяснить? Неужели мы сталкиваемся с одним из странных ограничений F-связанного полиморфизма? – gzm0

+0

@ gzm0: Помогло ли мое обновление? –

Смежные вопросы