преобразование времени выполнения List в HList

Я хочу иметь общий список разных типов и хочу получать объекты определенного типа.

У меня есть эта структура:

trait Parent
case class A() extends Parent
case class B() extends Parent
case class C() extends Parent

Я могу определить разные списки с разным размером:

val list:List[Parent] = A() :: B() :: C() :: C() ::Nil //or any size or ordering

Я хочу передать это во время выполнения в Hlist из A, B, C, C. .toHlist[] нужны типы элементов, которые должны выводиться во время выполнения. Что было бы бесформенным? Есть ли способ преобразовать его в кортежи?


person Omid    schedule 12.12.2014    source источник
comment
Чего вы хотите достичь?   -  person ziggystar    schedule 12.12.2014
comment
Как ответили другие, как только вы перейдете к List[Parent], вся информация о времени компиляции об отдельных элементах в списке (которая требуется для создания HList) исчезнет. Это необратимая операция.   -  person Jesper Nordenberg    schedule 12.12.2014
comment
@ziggystar Мне нужно использовать что-то вроде этого: myHlist.filter[A], но из-за другого потока выполнения в моем коде это может быть что угодно. скажем, у нас есть условие, поэтому в одной ветке это может быть A::B::C::C, в другой может быть что-то совершенно другое, поэтому я не делаю порядок типов во время компиляции, есть ли способ, чтобы в каждая ветка, которую я определил, отличается? или есть ли другой способ получить ту же цель?   -  person Omid    schedule 12.12.2014


Ответы (2)


Вы не можете этого сделать. Обратите внимание, что

должен быть выведен во время выполнения

является противоречием. Вывод типа работает только во время компиляции.

Другими словами, когда вы пишете что-то вроде

val list: A :: B :: C :: C :: HNil = ...

тип переменной list известен во время во время компиляции. Невозможно присвоить тип переменной во время выполнения, это просто не имеет смысла. Предположим, это было бы возможно, и у вас был бы волшебный метод toHlistMagical:

val list: List[Parent] = A() :: B() :: C() :: C() :: Nil
val hlist = list.toHlistMagical  // infers to  A :: B :: C :: C :: HNil

Теперь давайте немного изменим его:

def getHlist(list: List[Parent]) = list.toHlistMagical

Какой тип возврата вы ожидаете от этой функции? Имейте в виду, что его можно вызывать с различными списками, а не только с теми, которые содержат экземпляры A, B, C, C в таком порядке:

getHlist(C() :: B() :: A() :: A() :: Nil)

Это может быть Any, но тогда вы все равно можете просто использовать List, потому что HList больше нет, поэтому вы не получаете никакой дополнительной безопасности типов.

Вот почему toHlist нужны типы:

def getHlist(list: List[Parent]) = list.toHlist[A :: B :: C :: C :: HNil]

getHlist теперь имеет возвращаемый тип Option[A :: B :: C :: C :: HNil], потому что вы указали именно тот тип, который вам нужен, а toHlist сможет выполнять проверку структуры list во время выполнения и возвращать Some, если список действительно содержит эти типы в этом порядке, или None, если нет.

person Vladimir Matveev    schedule 12.12.2014

Следующая функция может преобразовать ваш список в HList:

def listToHList(x: List[_]): HList = {
  if(x == Nil) HNil
  else x.head :: listToHList(x.tail)
}

Для вашего образца вы можете использовать его следующим образом:

listToHList(list).asInstanceOf[A :: B :: C :: HNil]

person Florian Kirmaier    schedule 08.10.2019