Using `String` instead of `Symbol` in `LabelledGen

2019-08-20 16:53发布

问题:

As indicated in both the Type Astronaut's Guide to shapeless (footnote 4), and Gitter April 5, 2018 3:35 PM, future versions of shapeless may change the key constraint of KeyTag (and therefore FieldType) from Symbol to String.

I am therefore trying to use string literals (supported in typelevel scala compiler, and also recent 2.12 releases with the -Yliteral-types flag) as the key type in my fields, to future-proof my code.

However, at present, all typeclasses using labels, particularly LabelledGeneric return FieldTypes with Symbols as keys. For instance:

scala> import shapeless._
import shapeless._

scala> case class Foo(bar : Int)
defined class Foo

scala> LabelledGeneric[Foo]
res0: shapeless.LabelledGeneric[Foo]{type Repr = Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("bar")],Int] :: shapeless.HNil} = shapeless.LabelledGeneric$$anon$1@56635171
                                                                                !!! ^^^^^^ !!!

So I'm trying to write an instance that converts LabelledGenerix.Aux.Repr between FieldType[S <: Symbol,_] and FieldType[S <: String,_], in the hope that in a future release, when the library macros/typeclasses are updated to return Strings, I will be able to simply remove that. I'm struggling to achieve this though. Essentially this boils down to implementing

      def syFldToStrFld[St <: String, Sy <: Symbol, T](syFld : FieldType[Sy,T])(implicit syWit : Witness.Aux[Sy]) : FieldType[St,T] =
        (syWit.value.name : String) ->> (syFld : T)

Which results in

[error] : Expression (syWit.value.name: String) does not evaluate to a constant or a stable reference value

Is there any way to work around this, at compile time? Or are there any other ways one could use Strings as keys in shapeless and have them interop with all the built-in library methods e.g. LabelledGeneric, Record, etc.?