Есть ли способ сопоставить набор значений типа, параметризованного более высоким типом?

Я прочитал существующие вопросы о том, что определения типов с параметризованными границами недопустимы внутри блоков (или что-то в этом роде), но это не помогает мне в моей проблеме:

type Cons[X]

class Higher[C[X] <: Cons[X]]
type AnyHigher = Higher[C] forSome { type C[X] <: Cons[X] }

Seq[AnyHigher]().map { h => h }

компилятор:

can't existentially abstract over parameterized type C
Seq[AnyHigher]().map { h => h }

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


person Turin    schedule 19.11.2020    source источник
comment
Вы уверены, что вам нужны экзистенциалы? они, как известно, трудны для понимания и использования, и была даже попытка удалить их из языка.   -  person Luis Miguel Mejía Suárez    schedule 19.11.2020
comment
Да, в Scala 3 их нет. Но, к сожалению, я не думаю, что есть другой способ определить LUB всех Higher экземпляров. И вся «параметризация с помощью конструктора типов» является абсолютно центральной для проекта, я никак не могу изменить определение. В худшем случае я введу запечатанный непараметризованный тип с методом приведения к экзистенциальному типу.   -  person Turin    schedule 19.11.2020
comment
почему именно вы хотите абстрагироваться от всего вышеперечисленного? вы смотрели на typeclass вместо этого?   -  person Luis Miguel Mejía Suárez    schedule 19.11.2020
comment
Классы типов предназначены для типов. Здесь у меня нет типа, только конструктор типа, потому что я использую фантомные типы для индексации на уровне типов Higher. , но это Const, которая является фактической переменной и полезной нагрузкой всего проекта.   -  person Turin    schedule 23.11.2020
comment
так что Monad не является классом типов, потому что он работает с конструкторами типов (которые, кстати, также являются типами)? - Если есть только один Минус, какой смысл абстрагироваться? - Наконец, я не говорю, что класс типов был бы решением, я просто спросил, зачем вам это нужно, поскольку из вопроса неясно, и просто сказал, что, возможно, класс типов будет работать.   -  person Luis Miguel Mejía Suárez    schedule 23.11.2020


Ответы (2)


Обходной путь

Seq[AnyHigher]().map(new (AnyHigher => AnyHigher) {
  override def apply(h: AnyHigher): AnyHigher = h
})

не может экзистенциально абстрагироваться от параметризованного типа...

Другой обходной путь — сделать C[X] членом типа, а не параметром типа.

type Cons[X]

class Higher {
  type C[X] <: Cons[X]
}
object Higher {
  type Aux[C0[X0] <: Cons[X0]] = Higher { type C[X] = C0[X] }
}

type AnyHigher = Higher

Seq[AnyHigher]().map(h => h)

и используйте Higher.Aux[C] вместо Higher[C] и Higher вместо Higher[C] forSome { type C[X] <: Cons[X] }.

http://dotty.epfl.ch/docs/reference/dropped-features/existential-types.html

https://scalacenter.github.io/scala-3-migration-guide/docs/incompatibilities/dropped-features.html#existential-type

Экзистенциальный тип — это отброшенная функция, что делает следующий код незаконным.

def foo: List[Class[T]] forSome { type T }

Предлагаемое решение состоит в том, чтобы ввести охватывающий тип, который содержит зависимый тип:

trait Bar {   
  type T   
  val value: List[Class[T]] 
}

def foo: Bar
person Dmytro Mitin    schedule 19.11.2020
comment
Спасибо! Быстро как всегда :) Я знаю, что они удаляются, но в Scala 3 это работает без экзистенциалов, подстановочный знак означает любой тип. Я пытаюсь кодировать с учетом запланированных изменений, но, к сожалению, слишком часто стиль scala 3 не компилируется в 2.13 - person Turin; 19.11.2020

Почему ответ @Dmytro Mitin является правильным, поскольку он безопасен для типов и предлагает локальное решение, не требующее изменений в типах, это немного сложно. Итак, по крайней мере временно, я решил ввести супертип и кастинг:

    sealed trait AnyHigher {
        def apply() :Higher[T] forSome { type T[O] <: Cons[O] } =
            this.asInstanceOf[Higher[T] forSome { type T[O] <: Cons[O] }]
    }
    
    class Higher[T[O] <: Cons[O]] extends AnyHigher

    Seq[AnyHigher]().map(t => t)

Это уродливо, но немного меньше, и это временно до Scala 3, у которого есть типы подстановочных знаков, охватывающие любые типы.

person Turin    schedule 19.11.2020