Экзистенциальный тип высшего рода

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

Мне кажется, что myBuilder соответствует типу MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }, где Element[X] соответствует MultiSignalElement[X], но компилятор говорит, что это не так. Похоже, это связано с тем, что Е является типом более высокого порядка. Почему это не работает, и есть ли способ это исправить?

  class MultiSignalElement[+T] {
  }

  abstract class MultiSignal[+T] {
    type Element[+X] <: MultiSignalElement[X]

    val element : Element[T]

    def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : R[T] =
      builder.buildNew(element)
  }

  abstract class MultiSignalBuilder[-E[+X] <: MultiSignalElement[X], +R[+X] <: MultiSignal[X]] {
    def buildNew[T](element : E[T]) : R[T]
  }

  object myBuilder extends MultiSignalBuilder[MultiSignalElement, MultiSignal] {
    def buildNew[T](e : MultiSignalElement[T]) = new MultiSignal[T]() {
      type Element[+X] = MultiSignalElement[X]

      val element = e
    }
  }

  val multiSignal = new MultiSignal[Int] {
    type Element[+X] = MultiSignalElement[X]

    val element = new MultiSignalElement()
  }

  multiSignal.transform(myBuilder) //type error on this line
  multiSignal.transform[MultiSignal](myBuilder) //type error on this line

person Nimrand    schedule 28.10.2015    source источник
comment
На самом деле я все еще не мог скомпилировать безэкзистенциальную версию со scala 2.11.7.   -  person Odomontois    schedule 28.10.2015
comment
Не могли бы вы дать более подробную информацию о мотивации этого фрагмента кода? Чего именно он должен достичь? Исправлять ошибки компиляции без понимания смысла кода довольно сложно...   -  person Andrey Tyukin    schedule 28.10.2015
comment
@Odomontois, Да, похоже, он скомпилировался. Но на самом деле ошибки компиляции просто вытеснялись другими ошибками проекта в других файлах. Итак, я удалил его.   -  person Nimrand    schedule 28.10.2015


Ответы (1)


Проведем пошаговый анализ.

Сначала у нас есть

def transform[R](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : Unit = { }

Что эквивалентно утверждению: существует

type E[+X] >: Element[X]

Для которого мы можем определить

def transform[E[+X] >: Element[X], R[+_]](builder : MultiSignalBuilder[E, R] ) : Unit = { }

Здесь у нас ошибка

Ошибка: (7, 18) ковариантный тип X встречается в контравариантной позиции в типе [+X] >: MultiSignal.this.Element[X] типа E

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

def transform[E[+X] <: Element[X], R[+_]](builder : MultiSignalBuilder[E, R] ) : Unit = { }

Теперь у нас есть

Ошибка: (7, 56) аргументы типа [E,R] не соответствуют ограничениям параметров типа класса MultiSignalBuilder [-E[+X] ‹: MultiSignalElement[X],+R[+X] ‹: MultiSignal[X]]

Поэтому мы забыли потребовать подтипа MultiSignal[X] из параметра R.

Давайте изменим это

 def transform[E[+X] <: Element[X], R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] ) : Unit = { }

В настоящее время

multiSignal.transform[MultiSignalElement,MultiSignal](myBuilder)

Успешно компилируется.

Наконец-то мы смогли вернуться к экзистенциальной версии

def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome {type E[+X] <: Element[X]}) : Unit = { }

С которым

multiSignal.transform[MultiSignal](myBuilder)

Успешно компилируется.

Грустно

multiSignal.transform(myBuilder)

Все равно не компилируется. Я думаю, что компилятору нужно разрешить слишком много отношений типов.

person Odomontois    schedule 28.10.2015
comment
К сожалению, я не могу использовать E[+X] ‹: Element[X] по причинам, о которых вы не могли знать из-за сделанных мной упрощений. Смотрите мой обновленный вопрос с обновленным кодом. Я поиграю с этим и посмотрю, что я могу сделать, но, возможно, мне придется переосмыслить этот подход. Спасибо за помощь. - person Nimrand; 28.10.2015
comment
Думаю, я исправил это. Дело дошло до того, что я определил X как ковариантный в E в определении MultiSignalBuilder. Хотя это обычно верно, это ненужное ограничение. Как только я удалил это, я также мог удалить ковариацию X на E в параметре типа преобразования, и он скомпилировался. Даже вывод типов работает корректно. - person Nimrand; 28.10.2015