Gabriele Petronella Gabriele Petronella - 2 months ago 11
Scala Question

Pass a type parameter to be used as argument LabelledGeneric

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?

Answer

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).