为了学习Scala的宏系统,我想我会尝试编写一个基本的CPS转换宏。我已经为Clojure编写了一个相当全面的CPS转换框架,所以我对CPS转换本身非常熟悉。但是,我无法转换功能/方法应用程序。
对于CPS转换,函数调用如下形式:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
需要翻译成以下形式的表达式:
cps(f(<a>, <b>, <c>, ...))
显然,生成的延续lambdas(例如cps(<a>){ $a =>
cps(<b>){ $b =>
cps(<c>){ $c =>
... => f($a, $b, $c, ...)
}
}
}
)的参数需要是新符号,因此它们不会无意中与词汇上下文中的变量名冲突。因此,对于每个参数$a
,我生成一个新名称:
arg
(其中val name = Ident(TermName(c.freshName))
是宏的c
),然后我在下面的quasiquote中使用它:
Context
其中q"""cps(arg)($name => $remainder)"""
指的是计算的其余部分。
宏本身编译得很好,但是当我尝试将它与涉及函数应用程序的表达式一起使用时,我收到以下错误:
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
请注意,如果用注释行替换lambda表达式,它就可以工作。
所以我的问题:如何将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)""")
}
生成的名称用作匿名函数的参数名称?
答案 0 :(得分:-1)
我认为您需要ValDef
表单val $name: $T = _
,其中_
由NoTree
表示。使用_
初始化变量是有效的Scala,将对null
的引用和数字设置为0
(即默认值),但在ValDef
时也用作内部占位符} s(例如函数参数)但没有合理的默认值。
我在这里移动,所以我无法测试它。在任何情况下,如果q"a: Any => a"
不起作用,您可以在REPL中对值NoTree
进行解构,以查找编译器通常设置的默认值。