I'm trying to parametrize a method that needs to work on a generic type A
for which a LabelledGeneric
can be retrieved. Here's the naive approach
case class Foo(bar: String, baz: Boolean)
def params[A](a: A) = {
val lbl = LabelledGeneric[A]
val keys = Keys[lbl.Repr].apply
...
}
val myThingy = params(Foo)
Of course, the underlying macro complains. It doesn't know enough about A
:
type A is not a class or trait
So, I tried to have the LabelledGeneric
inferred
def params[A](a: A)(implicit lbl: LabelledGeneric[A]) = {
val keys = Keys[lbl.Repr].apply
...
}
this seems to work, but the Repr
type is not known to be an HList
anymore
type arguments [lbl.Repr] do not conform to method apply's type parameter bounds [L <: shapeless.HList]
Ok, let's try to be more precise
def params[A, Repr <: HList](a: A)(implicit lbl: LabelledGeneric.Aux[A, Repr]) = {
val keys = Keys[lbl.Repr].apply
...
}
Now, Repr
is definitely an HList
, but still Keys
cannot resolve its implicits
could not find implicit value for parameter values: shapeless.ops.record.Values[lbl.Repr]
Final attempt, let's try to have everything I need computed implicitly
def params[A, Repr <: HList](a: A)(implicit
lbl: LabelledGeneric.Aux[A, Repr],
kk: Keys[Repr]
) = {
val keys = kk.apply
...
}
Still no luck, apparently the first implicit cannot be resolved at call site
could not find implicit value for parameter lbl: shapeless.LabelledGeneric.Aux[example.Main.Foo.type,Repr]
[error] params(Foo)
Clearly all of this machinery works, when dealing directly with the specific type, e.g.
val lbl = LabelledGeneric[Foo]
val keys = Keys[lbl.Repr].apply
// no problem
I'm clearly missing the needed set of refinements on my type in the method signature, but I can get my head around what's going on here. Any idea?
The last variant with everything computed implicitly works for me,
scala> import shapeless._, ops.record._
import shapeless._
import ops.record._
scala> :paste
// Entering paste mode (ctrl-D to finish)
def params[A, Repr <: HList](a: A)
(implicit lbl: LabelledGeneric.Aux[A, Repr], kk: Keys[Repr]) = {
val keys = kk.apply
keys
}
// Exiting paste mode, now interpreting.
params: ...
scala> case class Foo(bar: String, baz: Boolean)
defined class Foo
scala> params(foo)
res0: ... = 'bar :: 'baz :: HNil
(result types elided for readability).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With