Shapeless:如何表达 <: case class type param for Generix.Aux

Shapeless: How to express <: case class type param for Generix.Aux

我有以下代码来基本上遍历 case class 的字段并使用 Poly 将它们映射到相同的类型并使用 ToList[HL, Out]

为简单起见,我们可以假设 Poly 这样做:

object Schema extends Poly1 {
  implicit def caseInt = at[Int](_ => "I'm an int")
  implicit def caseString = at[String](_ => "Oh boy a string")
}

def infer[V1 <: Product, Out <: HList, MapperOut <: HList](v1: V1)(
  implicit gen: Generic.Aux[V1, Out],
    map: Mapper.Aux[Schema.type, Out, MapperOut],
    to: ToList[MapperOut, String]
): List[String] = to (gen to v1 map Schema)

这一切都非常简单,适用于简单的场景:

case class Test(id: Int, text: String)
val list = infer(Test(2, "text"))
// List("I'm an int", "Oh boy a string")

现在要去公交车不去的地方运行:

class Automagical[T <: Product with Serializable : TypeTag] {
  def instance: T 
  // The typetag bit is needed for something else
  def convert: List[String] = infer(instance)
}

可悲的是,对上面的任何调用都失败了:

could not find implicit value for parameter gen: shapeless.Generic.Aux[T,Out]

奖金

如何通过根本不需要 T 的实例来改进 infer 方法?显然类型推断很好,但我确实需要以某种方式从 HList[Lub] 中具体化 List[String] 并映射到某些东西上。

鉴于我只关心类型,是否可以通过仅知道要被多映射编码为 HList?

的类型来派生 List[String] 的具体实例

类似于:

 def infer[V1 <: Product, Out <: HList, MapperOut <: HList]()(
  implicit gen: Generic.Aux[V1, Out],
    map: Mapper.Aux[Schema.type, Out, MapperOut],
    to: ToList[MapperOut, String]
): List[String] = {
  // Magically build an HList with samples from its types.
  // Or an alternative approach that gives the same outcome
  val reifiedInstance = reify[Out]
  to (reifiedInstance map Schema)
}

为确保 convert 可以访问 infer 的隐式参数,它们必须在创建 Automagical 实例时存在:

abstract class Automagical[T <: Product with Serializable : TypeTag,
    Out <: HList, MapperOut <: HList]
  (implicit
    gen: Generic.Aux[T, Out],
    map: Mapper.Aux[Schema.type, Out, MapperOut],
    to: ToList[MapperOut, String]) {
  def instance: T
  // The typetag bit is needed for something else
  def convert: List[String] = infer(instance)
}