Что работает (часть A)
Предположим, что у меня есть черта с параметром типа:
trait A[T]
Я могу использовать экзистенциальный тип для записи метода, который возьмет коллекцию A
, у которой все те же T
:
def foo(as: Seq[A[X]] forSome { type X }) = true
Обратите внимание, что это отличается от следующего:
def otherFoo(as: Seq[A[X] forSome { type X }]) = true
Или эквивалент:
def otherFoo(as: Seq[A[_]]) = true
В этих случаях объем экзистенциальности находится внутри Seq
, поэтому A
может иметь разные T
s. С моим оригинальным foo
(с экзистенциальным охватом над Seq
), все в порядке:
foo(Seq(new A[Int] {}, new A[Int] {}))
Но измените параметры типа и не скомпилируйте:
scala> foo(Seq(new A[Int] {}, new A[String] {}))
<console>:10: error: type mismatch;
found : Seq[A[_ >: java.lang.String with Int]]
required: Seq[A[X]] forSome { type X }
foo(Seq(new A[Int] {}, new A[String] {}))
^
Это все довольно просто.
Что работает (часть B)
Теперь предположим, что у меня есть аналогичная черта с членом типа вместо параметра типа:
trait B { type T }
Я могу написать метод, который будет принимать только B
с некоторым заданным T
:
scala> def bar[X](b: B { type T = X }) = true
bar: [X](b: B{type T = X})Boolean
scala> bar[Int](new B { type T = Int })
res5: Boolean = true
scala> bar[String](new B { type T = Int })
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = String}
bar[String](new B { type T = Int })
^
Опять же, это работает точно так, как вы ожидали.
Что не работает
Когда мы пытаемся написать эквивалент нашего foo
выше, но для членов типа вещи становятся странными.
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
baz: (as: Seq[B{type T = X}] forSome { type X })Boolean
scala> baz(Seq(new B { type T = Int }, new B { type T = String }))
res7: Boolean = true
То, что последняя компиляция строк не имеет для меня никакого смысла. Я сказал, что хочу, чтобы все члены типа были одинаковыми. Мой foo
показывает, что я могу сделать это для параметров типа, а bar
показывает, что я могу ограничить тип, основанный на его членах типа. Но я не могу объединить эти два.
Я пробовал это на 2.9.2 и 2.10.0-M5.
Мотивация
Этот вопрос вдохновлен этим, где моя первая мысль была, о, просто используйте экзистенциальный тип (отбросив на секунду проблему, которая представляется невозможным получить экзистенциальный тип для области типа повторяющегося параметра, что было бы удобно здесь):
def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
Но это на самом деле не работает - вы получаете тот же странный результат, что и в упрощенном примере выше.