Я пробыл слишком поздно прошлой ночью, пытаясь разобраться в этом безжизненном вопросе, и я боюсь, что он собирается съесть мой вечер, если я не сдержу его с груди, так что здесь идет.
В этой минимизированной версии я просто определяю класс типа, который будет рекурсивно преобразовывать классы 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 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
} = [email protected]
scala> DeepHLister[B :: HNil]
res1: DeepHLister[B :: HNil] {
type Out = (
(Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil
) :: HNil
} = [email protected]
scala> DeepHLister[C :: HNil]
res2: DeepHLister[C :: HNil] {
type Out = (
((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) ::
(Int :: String :: HNil) ::
HNil
) :: HNil
} = [email protected]
Пока все хорошо. Но тогда:
scala> DeepHLister[D :: HNil]
res3: DeepHLister[D :: HNil] {
type Out = ((Int :: String :: HNil) :: B :: HNil) :: HNil
} = [email protected]
Не удалось преобразовать 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
Мне не хватает?
Хорошо, спасибо за прослушивание - может быть, теперь я могу читать книгу или что-то в этом роде.