Странное поведение при попытке рекурсивно преобразовать классы дел в гетерогенные списки с помощью Shapeless

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

В этой минимизированной версии я просто определяю класс типов, который будет рекурсивно преобразовывать классы case вгетерогенный списки:

import shapeless._

trait DeepHLister[R <: HList] extends DepFn1[R] { type Out <: HList }

trait LowPriorityDeepHLister {
  type Aux[R <: HList, Out0 <: HList] = DeepHLister[R] { type Out = Out0 }

  implicit def headNotCaseClassDeepHLister[H, T <: HList](implicit
    dht: DeepHLister[T]
  ): Aux[H :: T, H :: dht.Out] = new DeepHLister[H :: T] {
    type Out = H :: dht.Out
    def apply(r: H :: T) = r.head :: dht(r.tail)
  }
}

object DeepHLister extends LowPriorityDeepHLister {
  implicit object hnilDeepHLister extends DeepHLister[HNil] {
    type Out = HNil
    def apply(r: HNil) = HNil
  }

  implicit def headCaseClassDeepHLister[H, R <: HList, T <: HList](implicit
    gen: Generic.Aux[H, R],
    dhh: DeepHLister[R],
    dht: DeepHLister[T]
  ): Aux[H :: T, dhh.Out :: dht.Out] = new DeepHLister[H :: T] {
    type Out = dhh.Out :: dht.Out
    def apply(r: H :: T) = dhh(gen.to(r.head)) :: dht(r.tail)
  }

  def apply[R <: HList](implicit dh: DeepHLister[R]): Aux[R, dh.Out] = dh
}

Давайте попробуем это! Для начала нам нужны классы case:

case class A(x: Int, y: String)
case class B(x: A, y: A)
case class C(b: B, a: A)
case class D(a: A, b: B)

И затем (обратите внимание, что я очистил синтаксис типа, чтобы не было нечитаемого беспорядка):

scala> DeepHLister[A :: HNil]
res0: DeepHLister[A :: HNil]{
  type Out = (Int :: String :: HNil) :: HNil
} = DeepHLister$anon$2@634bf0bf

scala> DeepHLister[B :: HNil]
res1: DeepHLister[B :: HNil] {
  type Out = (
    (Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil
  ) :: HNil
} = DeepHLister$anon$2@69d6b3e1

scala> DeepHLister[C :: HNil]
res2: DeepHLister[C :: HNil] {
  type Out = (
    ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) ::
    (Int :: String :: HNil) ::
    HNil
  ) :: HNil
} = DeepHLister$anon$2@4d062faa

Все идет нормально. Но потом:

scala> DeepHLister[D :: HNil]
res3: DeepHLister[D :: HNil] {
  type Out = ((Int :: String :: HNil) :: B :: HNil) :: HNil
} = DeepHLister$anon$2@5b2ab49a

B не был преобразован. Если мы включим-Xlog-implicits это последнее сообщение:

<console>:25: this.DeepHLister.headCaseClassDeepHLister is not a valid implicit value for DeepHLister[shapeless.::[B,shapeless.HNil]] because:
hasMatchingSymbol reported error: diverging implicit expansion for type DeepHLister[this.Repr]
starting with method headNotCaseClassDeepHLister in trait LowPriorityDeepHLister
              DeepHLister[D :: HNil]
                         ^

Что не имеет смысла для меняheadCaseClassDeepHLister должен быть в состоянии генерироватьDeepHLister[B :: HNil] просто отлично, и это так, если вы спросите об этом напрямую.

Это происходит как в 2.10.4, так и в 2.11.2, а также с выпуском 2.0.0 и мастером. Я почти уверен, что это ошибка, но я не исключаю, что я делаю что-то не так. Кто-нибудь видел что-нибудь подобное раньше? Что-то не так с моей логикой или ограничениемGeneric Я скучаю?

Хорошо, спасибо, что выслушали, может быть, теперь я могу пойти почитать книгу или еще что-нибудь.

Ответы на вопрос(2)

Ваш ответ на вопрос