Compiler Cannot Find Correct Implications for Formless LabelledGeneric

Continuing the discussion of converting case classes and Map[String,Any] , I encountered some problems when I wanted to use it in a general way. Here is the main discussion.

And when I want to use a general method, like the following, the compiler complains about implicits:

 import MapConvertor._ def convert[A](cc: A)= { cc.toMapRec } 

Here is all the code that toMapRec provides:

 import shapeless._, labelled.FieldType, record._ trait ToMapRec[L <: HList] { def apply(l: L): Map[String, Any] } trait LowPriorityToMapRec { implicit def hconsToMapRec1[K <: Symbol, V, T <: HList](implicit wit: Witness.Aux[K], tmrT: ToMapRec[T] ): ToMapRec[FieldType[K, V] :: T] = new ToMapRec[FieldType[K, V] :: T] { def apply(l: FieldType[K, V] :: T): Map[String, Any] = tmrT(l.tail) + (wit.value.name -> l.head) } } object ToMapRec extends LowPriorityToMapRec { implicit val hnilToMapRec: ToMapRec[HNil] = new ToMapRec[HNil] { def apply(l: HNil): Map[String, Any] = Map.empty } implicit def hconsToMapRec0[K <: Symbol, V, R <: HList, T <: HList](implicit wit: Witness.Aux[K], gen: LabelledGeneric.Aux[V, R], tmrH: ToMapRec[R], tmrT: ToMapRec[T] ): ToMapRec[FieldType[K, V] :: T] = new ToMapRec[FieldType[K, V] :: T] { def apply(l: FieldType[K, V] :: T): Map[String, Any] = tmrT(l.tail) + (wit.value.name -> tmrH(gen.to(l.head))) } } object MapConvertor { implicit class ToMapRecOps[A](val a: A) extends AnyVal { def toMapRec[L <: HList](implicit gen: LabelledGeneric.Aux[A, L], tmr: ToMapRec[L] ): Map[String, Any] = tmr(gen.to(a)) } } 
+3
scala generic-programming shapeless
Jul 26 '15 at 23:02
source share
1 answer

You will need to prove that the record representing A has an instance of ToMapRec , which you can do as follows:

 def convert[A, R <: HList](cc: A)(implicit gen: LabelledGeneric.Aux[A, R], tmr: ToMapRec[R] ) = tmr(gen.to(cc)) 

You can also introduce a new type class to clear it a bit:

 trait CcToMapRec[A] { def apply(a: A): Map[String, Any] } object CcToMapRec { implicit def ccToMapRec[A, R <: HList](implicit gen: LabelledGeneric.Aux[A, R], tmr: ToMapRec[R] ): CcToMapRec[A] = new CcToMapRec[A] { def apply(a: A): Map[String, Any] = tmr(gen.to(a)) } } 

And then your method needs only one implicit parameter:

 def convert[A](cc: A)(implicit ctmr: CcToMapRec[A]) = ctmr(cc) 

But you still need to insert this instance with any method with a common type that you are going to convert.

+4
Jul 26 '15 at 23:56
source share



All Articles