标记案例 class 上的 LabelledGeneric 实例生成在 shapeless 中产生错误

LabelledGeneric instance generation on a tagged case class yields me an error in shapeless

我试图从来自另一个 HList(确切地说是另一个 LabelledGeneric)的标记类型中获取一个 LabelledGeneric 实例,但是编译器给我一个错误,说它找不到隐式。

准确的错误是(启用-x-log-implicits):

shapeless.this.DefaultSymbolicLabelling.mkDefaultSymbolicLabelling is not a valid implicit value for shapeless.DefaultSymbolicLabelling.Aux[Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner],K] because:
hasMatchingSymbol reported error: Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner] is not case class like or the root of a sealed family of types

这是片段:

case class Inner(a: Int)
case class Outer(b: Int, c: Inner)

val gen = LabelledGeneric[Outer]

val inner = Inner(1)
val outer = Outer(2, inner)

def getGen[A, L](x: A)(implicit gen: LabelledGeneric.Aux[A, L]) = gen

val hOuter = gen.to(outer)

getGen(hOuter.at(1))

我是不是漏掉了什么明显的东西?

谢谢。

编辑:

我添加了案例的定义类。我也在使用 scala 2.11.8 和 shapeless 2.3.0

LabelledGeneric[Outer]Outer 类型的值放入无形记录中。这些是 HList 个字段,每个字段都是一个标记有其 "label" 的值 ... 与案例 class 中的字段名称相对应的单例类型。类型 T 的标记值是类型 T 的子类型,但这两种类型并不相同。通常这绝对没问题。

在您的场景中,您使用的是FieldType['c.type, Inner] 类型的字段hOuter.at(1)。这是一个类型别名,扩展为以下内容,

Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]

然后您请求与该类型对应的 LabelledGeneric 实例。不幸的是,虽然 Inner 有一个 LabelledGeneric 实例,但 FieldType['c.type, Inner] 没有实例,因为正如编译器错误消息所说(扩展类型),

Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
is not case class like or the root of a sealed family of types

如果您实际上没有将标签用于任何事情,那么最简单的解决方法是在整个过程中使用 Generic 而不是 LabelledGeneric,或者至少在 [=26] 的定义中=].

如果您正在使用标签,那么解决您的问题的方法是将它们从字段中删除。做到这一点的最简单的方法,将在这里工作但不会概括,是依靠 Inner 作为 FieldType['c.type, Inner] 的子类型并使用类型归属,

getGen(hOuter.at(1): Inner)

这意味着 getGen 的类型参数 A 将被推断为 Inner 并且 LabelledGeneric[A] 的隐式查找将成功。

更通用的解决方案是使用 shapeless 的 Values 类型 class,它采用无形记录并剥离其每个元素的标签,从而产生一个 HList,仅包含值。