Reputation: 103
I'm trying to get a LabelledGeneric instance from a tagged type coming from another HList (another LabelledGeneric to be exact), but the compiler yields me an error saying that it cannot find the implicit.
The exact error is (enabling -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
This is the snippet:
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))
Am I missing something obvious here?
Thanks.
EDIT:
I added the definitions of the case classes. I'm also using scala 2.11.8 and shapeless 2.3.0
Upvotes: 4
Views: 532
Reputation: 23046
LabelledGeneric[Outer]
takes values of type Outer
onto shapeless records. These are HList
s of fields, each of which is a value tagged with its "label" ... a singleton type corresponding to the name of the field in the case class. A labelled value of type T
is a subtype of type T
, but the two types are not the same. Usually this is absolutely fine.
In your scenario you are taking the field hOuter.at(1)
which is of type FieldType['c.type, Inner]
. This is a type alias which expands to the following mouthful,
Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
You then ask for the LabelledGeneric
instance corresponding to that type. Unfortunately, whilst there is a LabelledGeneric
instance for Inner
, there's no instance for FieldType['c.type, Inner]
, because, as the compiler error message says (wrt the expanded type),
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
If you're not actually using the labels for anything, then the simplest fix for this is to use Generic
instead of LabelledGeneric
throughout, or at least in the definition of gen
.
If you are using the labels then the solution to your problem here is to strip them off the fields. The simplest way of doing that, which will work here but doesn't generalize, is to rely on Inner
being a subtype of FieldType['c.type, Inner]
and use a type ascription,
getGen(hOuter.at(1): Inner)
This means that the type parameter A
of getGen
will be inferred as Inner
and the implicit lookup for LabelledGeneric[A]
will succeed.
A more general solution would make use of shapeless's Values
type class which takes a shapeless record and strips the labels off each of its elements yielding an HList
consisting of just the values.
Upvotes: 3