Бесформенный тип возврата HList

#scala #generics #typeclass #implicit #shapeless

#scala #общие #класс типов #неявный #бесформенный

Вопрос:

Я пытаюсь включить немного shapeless в свой код и сталкиваюсь с досадно ранним препятствием. В приведенном ниже примере кажется, что HCON-добавление неопределенного объекта в HNil:

 trait HasValue[A, B] {
  def get(a: A): B
  def getAll[L <: HList, O <: HList](a: A)(implicit ga: GetAll[A, L]): O = ga.getAll(a, HNil)
}

trait GetAll[A, B] {
  def getAll[L <: HList, O <: HList](a: A, l: L): O
}
implicit def getAllIfHasValue[A, B](implicit ev: HasValue[A, B]) = new GetAll[A, B] {
  def getAll[L <: HList, O <: HList](a: A, l: L): O = ev.get(a) :: l
}
  

и получение ошибки — type mismatch: Found B :: L, Required O .
Я бы подумал, что, поскольку L сам является an HList , B :: L сам должен быть an HList , и поэтому все должно быть хорошо. Но, очевидно, нет.

Любая помощь приветствуется!

Комментарии:

1. Неясно, чего вы пытаетесь достичь. getAll подпись выглядит подозрительно: в ней говорится, что для каждого типа списка HList L и O вы можете создавать O только на основе L и A . Эта функция не имеет разумных реализаций (кроме возврата HNil always). Возможно, вы захотите перейти L и O к списку параметров типа признака.

2. @simpadjo — Да — я не использовал здесь хороший пример. Одна вещь, которая немного сбила меня с толку в примерах, которые я читал, заключалась в том, что люди склонны использовать синтаксис (при использовании HList в качестве аргументов функции или возвращаемых типов), скажем, def f[L <: HList]: L = 1 :: HNil . Для меня не сразу очевидно, зачем L здесь нужен параметр type. Почему не просто def f: HList = 1 :: HNil ?

3. HList тип ничего не говорит о типах его элемента. L предполагается, что он также содержит информацию об элементах.

4. @Chrisper, кстати, def f[L <: HList]: L = 1 :: HNil неверно. Это как если бы я написал def f[A]: A = 1 . Я думаю, вам следует подумать, что означают параметры типа в Scala.

5. @Chrisper Если вы пишете, у которого 1 :: HNil есть тип HList , вы теряете информацию об уровне типа Int :: HNil . HList не лучше, чем List[Any] .

Ответ №1:

Я думаю, ошибка довольно ясна

 type mismatch;
 found   : B :: L
 required: O
  

ev.get(a) :: l имеет тип B :: L , но O ожидается.

Я бы подумал, что, поскольку L сам является an HList , B :: L сам должен быть an HList , и поэтому все должно быть хорошо.

B :: L действительно HList , это an . Проблема в том, что B :: L это не O так .

И когда вы пишете подпись

 def getAll[L <: HList, O <: HList](a: A, l: L): O = ???
  

это означает, что для любого типа L <: HList и любого типа O <: HList , имеющего значения a: A и l: L производящего значение типа O . Я думаю, это не то, что вы хотели.

Может быть, вы хотели вернуть тип O в зависимости от типов A , B . Затем вы можете ввести параметр типа

 trait GetAll[A, B] {
  type O
  def getAll[L <: HList](a: A, l: L): O
}
  

Или, может быть, вы хотели вернуть тип O в зависимости от типов A , B , L <: HList . Тогда дополнительно вам следует перейти L на уровень признака

 trait GetAll[A, B, L <: HList] {
  type O
  def getAll(a: A, l: L): O
}
  

Комментарии:

1. спасибо — да, я думаю, у меня возникла некоторая путаница в отношении того, как параметры типа работают в таких контекстах. Основная проблема (которую мой первоначальный пример был плохим представлением), которую я теперь выяснил.