Quasiquotes sind erstaunlich - sie machen das Schreiben von Makros in Scala sehr viel weniger schmerzhaft, und meiner Erfahrung nach funktionieren sie fast immer genau so, wie ich es erwarten würde. Und das Beste von allem, sie sind jetzt in Scala 2.10 as a plugin verfügbar.Quasiquotes für mehrere Parameter und Parameterlisten
Diese Frage bezieht sich auf ein kleines Problem, das ich beim Schreiben this blog post stieß. Es steht auf meiner Liste, auf die ich achten muss, wenn ich ein paar Minuten finde, aber ich dachte mir, ich würde es hier posten, falls jemand anderes mich dazu bringen könnte und anderen Leuten zu helfen, die die gleiche Frage haben.
Angenommen habe ich eine Liste von Listen von Namen-Typ-Paare:
val pss = List(
List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]),
List(newTermName("z") -> typeOf[String])
)
Ich möchte diese in einen Baum verwandeln, die wie folgt aussieht:
def foo(x: Int, y: Char)(z: String) = ???
Die folgenden funktioniert gut:
q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???"
das heißt, es baut den folgenden Baum:
def bar(x: Int) = ???
was darauf schließen lässt, dass ich in der Lage sein sollte, so etwas zu schreiben:
val quoted = pss.map(_.map { case (n, t) => q"$n: $t" })
q"def foo..${quoted.map(ps => q"($ps)")} = 1"
Oder ein wenig einfacher, mit mehreren Parametern in einer einzigen Parameterliste:
q"def baz(..${quoted.head}) = ???"
Weder Werke -Ich bekomme Fehler wie folgt:
<console>:28: error: type mismatch;
found : List[c.universe.Typed]
required: List[c.universe.ValDef]
q"def baz(..${quoted.head}) = ???"
^
Fair genug-ich kann se e, wie es zum Quasiquoter aussehen würde, als ob ich getippte Ausdrücke eher baue, als Parameter in quoted
zu definieren. Keines der offensichtlichen Dinge, die ich mir vorstellen konnte, funktionierte (Hinzufügen = _
, ausdrückliche Eingabe der Quasiquote als ValDef
, etc.).
Ich weiß, dass ich manuell die Parameterdefinitionen aufbauen kann:
val valDefs = pss.map(
_.map {
case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree)
}
)
Und nun die baz
Version (mit einer Parameterliste) funktioniert:
q"def baz(..${valDefs.head}) = ???"
Aber nicht die foo
Version (die mit mehreren Parameterlisten).
So gibt es zwei Fragen hier. Erstens, wie kann ich Quasiquotes verwenden, um ein Name-Typ-Paar in einen Parameter ValDef
außerhalb des Kontexts einer in Anführungszeichen gesetzten Parameterliste umzuwandeln? Und zweitens, wie kann ich eine Liste von Listen mit Parameterdefinitionen in mehrere Parameterlisten umwandeln?
Es ist einfach genug, auf die manuelle AST-Konstruktion für das ganze verdammte Ding zurückzugreifen (siehe my post für ein Beispiel), aber ich möchte stattdessen Quasiquotes verwenden können.
1) Ich glaube, q "val $ n: $ t" wird 2 arbeiten) Verwenden Sie ... $ Listen von Listen spleißbar –
"val" funktioniert hier perfekt - danke! '... $ quoted' tut das aber nicht, da die inneren Listen nicht automatisch in Parameterlisten übernommen werden? –