Quasiquotes sono sorprendenti: rendono estremamente difficile la scrittura di macro in Scala, e nella mia esperienza funzionano quasi sempre esattamente come mi aspetterei. E soprattutto, ora sono disponibili as a plugin in Scala 2.10.Quasiquote per più parametri e liste di parametri
Questa domanda riguarda un piccolo problema che ho riscontrato durante la scrittura di this blog post. È sulla mia lista di cose da esaminare quando riesco a trovare qualche minuto, ma ho pensato di postarlo qui nel caso in cui qualcun altro mi potesse battere e per aiutare altre persone che si imbattono nella stessa domanda.
Supponiamo che io ho una lista di liste di coppie nome-tipo:
val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
Voglio trasformare questi in un albero che assomiglia a questo:
def foo(x: Int, y: Char)(z: String) = ???
I seguenti funziona bene:
q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???"
Cioè, si costruisce la seguente struttura:
def bar(x: Int) = ???
il che suggerisce che dovrei essere in grado di scrivere qualcosa del genere:
val quoted = pss.map(_.map { case (n, t) => q"$n: $t" })
q"def foo..${quoted.map(ps => q"($ps)")} = 1"
O un po 'più semplice, con parametri multipli in un unico elenco di parametri:
q"def baz(..${quoted.head}) = ???"
Né opere -Vengo errori come questo:
<console>:28: error: type mismatch;
found : List[c.universe.Typed]
required: List[c.universe.ValDef]
q"def baz(..${quoted.head}) = ???"
^
Abbastanza Giusto-posso vedere e come sembrerebbe al quasiquoter come sto costruendo espressioni tipizzate piuttosto che definire parametri in quoted
. Nessuna delle cose ovvie che potrei pensare di provare ha funzionato (aggiungendo = _
, digitando esplicitamente la quasiquote come ValDef
, ecc.).
so che posso costruire le definizioni dei parametri manualmente:
val valDefs = pss.map(
_.map {
case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree)
}
)
E ora la baz
versione (con una lista di parametri) Works:
q"def baz(..${valDefs.head}) = ???"
Ma non la versione foo
(quella con più liste di parametri).
Quindi ci sono due domande qui. Innanzitutto, come posso usare quasiquotes per trasformare una coppia nome-tipo in un parametro ValDef
al di fuori del contesto di un elenco di parametri quotati? E in secondo luogo, come posso trasformare un elenco di liste di definizioni di parametri in più liste di parametri?
È abbastanza facile ricorrere alla costruzione AST manuale per l'intera dannata cosa (vedere my post per un esempio), ma mi piacerebbe poter usare invece quasiquotes.
1) Credo q "val $ n: $ t" funzionerà 2) Utilizzare ... $ impiombare liste di liste –
'val' funziona perfettamente qui-grazie! "... $ quoted', tuttavia, non credo, perché le liste interne non vengono automaticamente aggiunte agli elenchi di parametri? –