Псевдоним типа A не эквивалентен A?

Этот код компилируется так же хорошо:

type Named[A] = (String, A)

def foo[A](a: A) = {}

trait Elem[A]

val m = Map[String, Elem[_]]()

m.foreach(e => foo[Named[Elem[_]]](e))

Однако это не так:

type NamedElem[A] = Named[Elem[A]]

m.foreach(e => foo[NamedElem[_]](e))

Сообщение об ошибке на самом деле не объясняет мне, почему:

type mismatch;
 found   : (String, Elem[_])
 required: NamedElem[_]
    (which expands to)  (String, Elem[_$2]) forSome { type _$2 }
              Map[String, Elem[_]]().foreach(e => foo[NamedElem[_]](e))
                                                                    ^

Так что, видимо, NamedElem[A] не Named[Elem[A]]. Это предполагаемое поведение? Или я что-то упускаю?

Благодарю вас!


person Ryoichiro Oka    schedule 24.12.2014    source источник


Ответы (1)


Это относится только к экзистенциальным типам. Это компилируется просто отлично:

type Named[A] = (String, A)

def foo[A](a: A) = {}

trait Elem[A]

val m = Map[String, Elem[Int]]()

m.foreach(e => foo[Named[Elem[Int]]](e))

type NamedElem[A] = Named[Elem[A]]

m.foreach(e => foo[NamedElem[Int]](e))

_ — это просто синтаксический сахар для forSome. В твоем случае:

NamedElem[_] заменяется на (String, Elem[T]) forSome { type T }, а Named[Elem[_]] заменяется на (String, Elem[T] forSome { type T })

Так что да, NamedElem[_] и Named[Elem[_]] - это разные типы.

Вы можете найти больше информации в моем старом вопросе: Экзистенциальные типы в Scala

person dk14    schedule 24.12.2014
comment
Спасибо @dk14, так что Named[Elem[A]] не NamedElem[A], когда A является экзистенциальным типом. Как вы думаете, мы можем предотвратить разницу? Я имею в виду, есть ли способ объявить type NamedElem[A], который полностью эквивалентен Named[Elem[A]]? - person Ryoichiro Oka; 24.12.2014
comment
@RyoichiroOka Это эквивалентно для каждого типа A. Проблема в том, что _ не является типом. - person Alexey Romanov; 24.12.2014
comment
Есть только способ объявить соответствующие экзистенциальные (если они вам очень нужны) - type NamedElem_ = Named[Elem[T] forSome { type T}]. Как сказал @Alexey Romanov - это уже эквивалентно для дженериков не высокого порядка. Попытка унифицировать его не имеет смысла ... просто посмотрите на дешугаринг - _ это просто синтаксический сахар для forSome, а не сам тип. Определение экзистенциального типа здесь {type T} внутри forSome, даже не T внутри Elem[T] (это просто ссылка) - person dk14; 24.12.2014
comment
forSome прикрепляется к ближайшим фигурным скобкам [_], поэтому на самом деле работает так, как ожидалось. - person dk14; 24.12.2014