Dans un effort pour apprendre le système de macro Scala, je pensais que je vais essayer ma main à l'écriture d'une macro de transformation CPS de base. J'ai déjà écrit un cadre de transformation CPS assez complet pour Clojure, donc je suis assez familier avec la transformation CPS elle-même. Cependant, je suis coincé transformant des applications de fonction/méthode.Comment utiliser l'identificateur frais dans la liste des paramètres de fonction Scala macro
Pour la CPS transform, les appels de fonction de la forme suivante:
cps(f(<a>, <b>, <c>, ...))
doivent se traduire par une expression de la forme:
cps(<a>){ $a =>
cps(<b>){ $b =>
cps(<c>){ $c =>
... => f($a, $b, $c, ...)
}
}
}
De toute évidence, les paramètres de la poursuite générés lambdas (par exemple, $a
) doivent être des symboles nouveaux afin qu'ils ne puissent pas entrer en conflit par inadvertance avec les noms de variables dans le contexte lexical. Donc, pour chaque argument arg
, je produis un nom frais:
val name = Ident(TermName(c.freshName))
(où c
est la de Context
macro) que je l'utilise ensuite dans le quasiquote suivant:
q"""cps(arg)($name => $remainder)"""
où remainder
fait référence au reste de le calcul.
La macro se compile bien, mais lorsque je tente de l'utiliser avec une expression qui implique une application de fonction, je reçois l'erreur suivante:
... exception during macro expansion:
[error] java.lang.IllegalArgumentException: fresh$macro$1 is not valid representation of a parameter, consider reformatting it into q"val $name: $T = $default" shape
Cependant, je ne pense pas qu'il est possible d'effectuer le "reformatage" recommandé, car il n'y a pas de $default
à fournir.
Voici un exemple minimal qui illustre la question que je vais avoir:
def id[A](expr : A) : A = macro idImpl[A]
def idImpl[A](c : blackbox.Context)(expr : c.Expr[A]) : c.Expr[A] = {
import c.universe._
val name = Ident(TermName(c.freshName))
//c.Expr(q"""val $name = $expr; $name""")
c.Expr(q"""($name => $name)($expr)""")
}
Notez que cela fonctionne si vous remplacez l'expression lambda avec la ligne commenté.
Ma question: Comment un nom généré par freshName
être utilisé comme nom de paramètre pour une fonction anonyme?
https://github.com/ReactiveMongo/ReactiveMongo/blob/master/macros/src/main/scala-2.12/MacroImpl.scala#L101 – cchantep
@cchantep, souhaitez-vous élaborer? Il ne semble pas y avoir de fonction définie par la macro là-bas. –
Si vous lisez attentivement, vous pouvez voir 'termName (..)' – cchantep