Есть ли способ получить значения для каждого члена HList из Scala Shapeless? - PullRequest
0 голосов
/ 05 апреля 2020

Я пробовал следующее:

type Params = String :: Int :: HNil

implicit val params: Params = "hello" :: 5 :: HNil

// Supposed to create an implicit for string and int if needed
implicit def meberImplicit[A](
  implicit 
  params: Params,
  selector: Selector[Params, A]
): A = params.select[A]

// Summoning a string
implicitly[String]    // compile-time error

Однако я получаю отклоняющуюся неявную ошибку:

diverging implicit expansion for type String

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

1 Ответ

1 голос
/ 05 апреля 2020

Проблема в том, что вы слишком универсальны c:

implicit def memberImplicit[A](
  implicit // what you put here is irrelevant
): A = ...

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

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

Дело в том, что тип, который вы возвращаете - A. Это означает, что даже если вы добавили туда какое-то ограничение, например, например, A =:!= Params - хотя обычно это будет работать ... вы просто предоставили все эти импликации, поэтому ограничения типов перестали работать, и внезапно производные для таких вещей, как, например, Selector[Params, String], имеют больше один из способов быть воплощенным. В этой ситуации практически любая реализация, которую вы попробуете - до тех пор, пока она вернет A, - потерпит неудачу.

Чтобы все работало, вы ДОЛЖНЫ ограничить вывод тем, что он не будет соответствовать всем - На самом деле, чем меньше совпадений, тем лучше. Например, создайте отдельный класс типов для извлечения значений из HLists:

trait Extractable[A] { def extract(): A }
object Extractable {
  implicit def extractHList[H <: HList, A](
    implicit
    h: H,
    selector: Selector[H, A]
  ): Extractable[A] = () => selector(h)
}

def extract[A](implicit extractable: Extractable[A]): A = extractable.extract()

, а затем

extract[String] // "hello"
...