找不到LabelledGeneric的无形Mapper

时间:2015-07-23 21:45:43

标签: scala shapeless hlist labelled-generic

我的基本类型池定义如下:

sealed trait Section
final case class Header(...) extends Section
final case class Customer(...) extends Section
final case class Supplier(...) extends Section
final case class Tech(...) extends Section

我想提供一些由此池中的类型组成的案例类,如下所示:

final case class ContractViewPartners(customer: Customer, supplier: Supplier)
final case class ContractView(header: Header, partners: ContractViewPartners, tech: Tech)

由于它们将大量用于通过使用here描述的方法透射到HList实现的特征生成器,我希望确保呈现类型的每个字段都是< / p>

  • Section子类型
  • {li> HList Section个子类型
  • 记录为HList子类型的Section

我已为此条件定义了简单的编译时检查程序:

object traverseView extends Poly1 {
  implicit def caseSection[S <: Section] = at[S](_ => ())

  implicit def caseSectionList[L <: HList]
  (implicit evt: ToTraversable.Aux[L, List, Section]) = at[L](_ => ())

  implicit def caseRecord[R, L <: HList]
  (implicit lgen: LabelledGeneric.Aux[R, L],
   trav: ToTraversable.Aux[L, List, Section]) = at[R](_ => ())
}

private def contractViewIsMultiSection(v: ContractView) =  {
  val gen = LabelledGeneric[ContractView].to(v)
  gen map traverseView
}

但它失败了(包名被删除)

  

无法找到参数映射器的隐含值:   Mapper [traverseView.type,:: [带KeyTag的标题] [带符号的符号]   Tagged [String(&#34; header&#34;)],Header],:: [ContractViewPartners with   KeyTag [符号与   Tagged [String(&#34; partners&#34;)],ContractViewPartners],:: [Tech with   KeyTag [带有标记的符号[String(&#34; tech&#34;)],Tech],HNil]]]

如果我从partners移除ContractView部分工作,如果我尝试在implicits上解析ContractViewPartners,我们也会找到它们。

在撰写问题时,我已经找到了添加.values之类的解决方案

private def contractViewIsMultiSection(v: ContractView) =  {
  val gen = LabelledGeneric[ContractView].to(v)
    .values //!!!
  gen map traverseView
}

可能是with KeyTag[...]类型无法正常作为LabelledGeneric转换的来源吗?

1 个答案:

答案 0 :(得分:3)

问题是Case是不变的,因此您拥有Case ContractViewPartners实例的事实并不意味着您拥有ContractViewPartners的案例实例带有类型级标签(只是ContractViewPartners的子类型)。你可以通过生成实例来直接解决这个问题。 FieldType[K, ContractViewPartners](对于某些任意K):

sealed trait Section
final case class Header(s: String) extends Section
final case class Customer(s: String) extends Section
final case class Supplier(s: String) extends Section
final case class Tech(s: String) extends Section

final case class ContractViewPartners(customer: Customer, supplier: Supplier)
final case class ContractView(header: Header, partners: ContractViewPartners, tech: Tech)

import shapeless._, labelled.FieldType, ops.hlist.ToList

object traverseView extends Poly1 {
  implicit def caseSection[S <: Section] = at[S](_ => ())

  implicit def caseSectionList[K, L <: HList](implicit
    lub: ToList[L, Section] 
  ) = at[FieldType[K, L]](_ => ())

  implicit def caseRecord[K, C, L <: HList](implicit
    gen: Generic.Aux[C, L],
    lub: ToList[L, Section] 
  ) = at[FieldType[K, C]](_ => ())
}

private def contractViewIsMultiSection(v: ContractView) =  {
  val gen = LabelledGeneric[ContractView].to(v)
  gen map traverseView
}

如果您不关心标签,也可以在Generic[ContractView]中使用contractViewIsMultiSection

但我建议不要使用Poly1来做这类事情。如果您只是想要证明类型是正确的,那么您可以使用自定义类型更干净一些。