Generic#to, but with Field Names?

211 Views Asked by At

Using Generic#to, I can get the HList representation of a case class:

import shapeless._
case class F(x: Int, y: String)

scala> Generic[F].to( F(1, "foo") )
res1: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 
    1 :: foo :: HNil

However, I'd like to get the following representation:

("x", 1) :: ("y", "foo") :: HNil

In other words, instead of just the F instance's fields' values, I'd like to get the field names, i.e. x and y, as well.

How can I get this representation?

1

There are 1 best solutions below

0
On BEST ANSWER

You're looking for LabelledGeneric.

In order to print the fields, you can then use the Fields type class (from the ops.record package), which can be invoked with .fields if you import also the record package.

Here's a full example

import shapeless._, record._, ops.record._
case class F(x: Int, y: String)    

scala> LabelledGeneric[F].to(F(1, "foo")).fields
res1: shapeless.::[(Symbol with shapeless.tag.Tagged[String("x")], Int),shapeless.::[(Symbol with shapeless.tag.Tagged[String("y")], String),shapeless.HNil]] = ('x,1) :: ('y,foo) :: HNil

If you also want to convert the keys to String:

object keysToString extends Poly1 {
  implicit def keyToName[A, B] = at[(Symbol with A, B)] { case (k, v) => (k.name, v) }
}

scala> LabelledGeneric[F].to(F(1, "foo")).fields.map(keysToString)
res2: shapeless.::[(String, Int),shapeless.::[(String, String),shapeless.HNil]] = (x,1) :: (y,foo) :: HNil