2015-07-28 9 views
271

Ich versuche ein Shapeless Makro von innerhalb einer quasiquote mit Scala zu nennen und ich bekomme nicht, was ich gerne bekommen würde.Wie man Shapeless in einer Quasiquote benutzt?

Mein Makro Rückkehr keine Fehler, aber es ist nicht erweitern Witness(fieldName) in Witness.Lt[String]

val implicits = schema.fields.map { field => 
    val fieldName:String = field.name 
    val fieldType = TypeName(field.valueType.fullName) 
    val in = TermName("implicitField"+fieldName) 
    val tn = TermName(fieldName) 
    val cc = TermName("cc") 
    q"""implicit val $in = Field.apply[$className,$fieldType](Witness($fieldName), ($cc: $className) => $cc.$tn)""" 
} 

Hier ist meine Field Definition:

sealed abstract class Field[CC, FieldName] { 
    val fieldName: String 
    type fieldType 

    // How to extract this field 
    def get(cc : CC) : fieldType 
} 

object Field { 
    // fieldType is existencial in Field but parametric in Fied.Aux 
    // used to explict constraints on fieldType 
    type Aux[CC, FieldName, fieldType_] = Field[CC, FieldName] { 
    type fieldType = fieldType_ 
    } 

    def apply[CC, fieldType_](fieldWitness : Witness.Lt[String], ext : CC => fieldType_) : Field.Aux[CC, fieldWitness.T, fieldType_] = 
    new Field[CC, fieldWitness.T] { 
     val fieldName : String = fieldWitness.value 
     type fieldType = fieldType_ 
     def get(cc : CC) : fieldType = ext(cc) 
    } 
} 

In diesem Fall wird die implizite ich generieren sieht aus wie :

implicit val implicitFieldname : Field[MyCaseClass, fieldWitness.`type`#T]{ 
    override type fieldType = java.lang.String 
} 

Wenn es Biene gewesen wäre n definiert außerhalb eines quasiquote würde es so etwas wie erzeugen:

implicit val implicitFieldname : Field.Aux[MyCaseClass, Witness.Lt[String]#T, String] = ... 

Gibt es etwas, das getan werden kann?

+0

Verwenden Sie dies in einer Makroannotation? Haben Sie versucht, eine Typannotation für '$ in' zu erstellen (was ich denke, dass Sie' ConstantType' benötigen)? –

+0

@TravisBrown ja Ich baue das mit einer Makro-Annotation (Macro Paradise). Ich habe versucht, einen Typ wie folgt anzugeben: '' 'q" "" implizite val $ in: Field.Aux [$ className, Witness.Lt [Zeichenfolge] #T, String] = Field.apply [$ className, $ fieldType ] (Witness ($ fieldName), ($ cc: $ className) => $ cc. $ Tn) "" "' '' – Roch

+0

Sie müssen jedoch den spezifischen Feldnamen in der Anmerkung des Typs eingeben (siehe z. B. mein altes Pre Shapeless 2.0 blog post [hier] (https://meta.plasm.us/posts/2013/06/28/singleton-types-for-literals-in-scala/) für ein Beispiel der Verwendung von 'ConstantType'). Haben Sie ein komplettes Arbeitsbeispiel? –

Antwort

1

Dies ist meine Arbeitslösung, die alte Makroanmerkungen verwendet.

import scala.language.experimental.macros 
import scala.reflect.macros.blackbox.Context 
import scala.annotation.StaticAnnotation 

class fieldable extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro fieldableMacro.impl 
} 

object fieldableMacro { 
    def impl(c: Context)(annottees: c.Expr[Any]*): c.Tree = { 
    import c.universe._ 
    annottees.map(_.tree) match { 
     case (param @ q"case class $className(..$fields)") :: Nil => { 
     val implicits = fields.collect { 
      case field @ q"$mods val $tname: $tpt" => q""" 
      implicit val $tname = Field.apply[$className,$tpt](
       Witness(${tname.decodedName.toString}), _.$tname 
      )""" 
     }; q"$param; object ${className.toTermName} {..$implicits}" 
     } 
    } 
    } 
} 

Es kann sich sicher sein, verbessert besser quasiquotes verwenden, aber mein Ziel war es etwas so sauberer wie möglich zu zeigen.

Es kann verwendet werden, wie:

@fieldable 
case class MyCaseClass(foo: String, bar: Int) 

Dies erzeugt ein MyCaseClass Begleiter Objekt Fields implicits erforderlich zu haben:

implicit val foo = Field.apply[MyCaseClass, String](Witness("foo"), ((x$1) => x$1.foo)); 
implicit val bar = Field.apply[MyCaseClass, Int](Witness("bar"), ((x$2) => x$2.bar)); 

Wie bereits hingewiesen wurde, ohne eine komplette Arbeits Zum Beispiel ist es ziemlich schwierig, eine erschöpfende Antwort zu schreiben.