I have basic type pool defined like that:
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
I'd like to present some case classes composed of types from this pool like this:
final case class ContractViewPartners(customer: Customer, supplier: Supplier)
final case class ContractView(header: Header, partners: ContractViewPartners, tech: Tech)
As they would be heavily used in feature-generators implemented via transfoming to HLists using method described here, I'd like to ensure that each field of presented type is one of
SectionsubtypeHListofSectionsubtypes- record presentable as
HListofSectionsubtypes
I've defined simple compile-time checker for this condition:
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
}
But it fails with (package names removed)
could not find implicit value for parameter mapper: Mapper[traverseView.type,::[Header with KeyTag[Symbol with Tagged[String("header")],Header],::[ContractViewPartners with KeyTag[Symbol with Tagged[String("partners")],ContractViewPartners],::[Tech with KeyTag[Symbol with Tagged[String("tech")],Tech],HNil]]]]
If i remove partners section from ContractView it's working and if i try to resolve implicits on ContractViewPartners they will be found too.
Again while writing question i've found solution with adding .values like that
private def contractViewIsMultiSection(v: ContractView) = {
val gen = LabelledGeneric[ContractView].to(v)
.values //!!!
gen map traverseView
}
Could it be that type with KeyTag[...] is not working properly as source for LabelledGeneric transformation?
The problem is that
Caseis invariant, so the fact that you have aCaseinstance forContractViewPartnersdoesn't mean that you have a case instance forContractViewPartnerswith a type-level label (which is only a subtype ofContractViewPartners). You can fix this pretty straightforwardly by generating instances for e.g.FieldType[K, ContractViewPartners](for some arbitraryK):You could also just use
Generic[ContractView]incontractViewIsMultiSectionif you don't care about the labels.I would probably suggest not using
Poly1for this kind of thing, though. If you just want evidence that the types are right, you could do that a little more cleanly with a custom type class.