Может быть, кто-то с лучшим пониманием бесформенного может дать вам лучший ответ.Согласно моему пониманию, проблема заключается в этапе вывода типа.Если вы указываете все типы явно, как в
val result: Foo[(Int, String)] = extract[(Foo[Int], Foo[String]),
Foo[Int] :: Foo[String] :: HNil,
Int :: String :: HNil]((Foo(1), Foo("a")))
, код правильно проверяет типы.Очевидно, что вы не хотите явно указывать эти типы.
Насколько я понимаю, компилятор не может вывести хорошие значения B
и tupler.Out
, поскольку они недостаточно тесно связаны с In
и A
.Один из способов обойти это - ввести промежуточную черту, например:
trait Extractor[L <: HList, HF] {
type FR <: HList
type TR
val folder: RightFolder.Aux[L, Foo[HNil], HF, Foo[FR]]
val tupler: Tupler.Aux[FR, TR]
}
object Extractor {
type Aux[L <: HList, HF, FR0 <: HList, TR0] = Extractor[L, HF] {type FR = FR0; type TR = TR0}
implicit def wrap[L <: HList, In, HF, FR0 <: HList, TR0](implicit folder0: RightFolder.Aux[L, Foo[HNil], HF, Foo[FR0]],
tupler0: Tupler.Aux[FR0, TR0]) = new Extractor[L, HF] {
type FR = FR0
type TR = TR0
override val folder = folder0
override val tupler = tupler0
}
}
, а затем использовать ее следующим образом:
def extract[In, A <: HList, B <: HList, C](keys: In)
(implicit gen: Generic.Aux[In, A],
extractor: Extractor.Aux[A, extractFold.type, B, C])
: Foo[C] = {
val hli = gen.to(keys)
val fr = extractor.folder(hli, Foo(HNil))
Foo(extractor.tupler(fr.a))
}
Это хакерское решение, но, по крайней мере, онокажется, работает (см. также онлайн демо ).