如何在Scala宏的函数参数列表中使用新标识符

如何在Scala宏的函数参数列表中使用新标识符,scala,macros,metaprogramming,Scala,Macros,Metaprogramming,为了学习Scala的宏系统,我想尝试编写一个基本的CPS转换宏。我已经为Clojure编写了一个相当全面的CPS转换框架,所以我对CPS转换本身非常熟悉。然而,我在转换函数/方法应用程序时遇到了困难 对于CPS转换,函数调用的形式如下: cps(f(<a>, <b>, <c>, ...)) (其中c是宏的上下文),我随后在以下准注释中使用它: q"""cps(arg)($name => $remainder)""" 其中,余数指计算的余数 宏本身编译

为了学习Scala的宏系统,我想尝试编写一个基本的CPS转换宏。我已经为Clojure编写了一个相当全面的CPS转换框架,所以我对CPS转换本身非常熟悉。然而,我在转换函数/方法应用程序时遇到了困难

对于CPS转换,函数调用的形式如下:

cps(f(<a>, <b>, <c>, ...))
(其中
c
是宏的
上下文
),我随后在以下准注释中使用它:

q"""cps(arg)($name => $remainder)"""
其中,
余数
指计算的余数

宏本身编译得很好,但当我尝试将其与涉及函数应用程序的表达式一起使用时,会出现以下错误:

... 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
但是,我认为不可能执行建议的“重新格式化”,因为没有提供
$default

下面是一个简单的例子,说明了我遇到的问题:

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)""")
}
请注意,如果将lambda表达式替换为注释行,则它可以工作


因此,我的问题是:
freshName
生成的名称如何用作匿名函数的参数名?

我认为您需要一个
ValDef
形式的
val$name:$T=
,其中
NoTree
表示。使用
\uuu
初始化变量是有效的Scala,将引用设置为
null
,将数字设置为
0
(即默认值),但当存在
ValDef
s(例如函数参数)但没有正常默认值时,也用作内部占位符


我在这里用手机,所以我不能测试。在任何情况下,您都可以对REPL中的值
q“a:any=>a”
进行分解,以查找编译器通常设置为默认值的内容(如果
NoTree
不起作用)。

@cchantep,是否要详细说明?那里似乎没有宏定义的任何函数。如果仔细阅读,您可以看到
TermName(..)
@cchantep,好的。。。不过,无论我是否使用
TermName
等包装,我仍然会遇到相同的错误。@cchantep,仔细看,似乎
TermName
就是解决方法。要么是我犯了一个错误,要么是我没有意识到错误已经变为抱怨“缺少参数类型”。如该错误所示,我还需要指定参数的类型,我可以从表达式树上的
tpe
属性(例如,
expr.tpe
)中获得该类型。谢谢,我不知道
\uucode>是默认值。然而,现在的问题是如何确定
T
。在我设计的例子中,它至少在理论上是简单的(尽管实现它的细节目前对我来说还很粗略)。但是在CPS的例子中,我想我需要从每个参数的树中推断出类型?
... 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
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)""")
}