Clojure 宏的求值

7

我在Clojure中构建DSL时遇到了问题。这是我从其他所有问题中分离出来的具体问题。

假设我们有一个简单的宏:

user> (defmacro m1 [x] `'~x)
#'user/m1 

它只是返回提供的字面量 用户>(m1 toUpperCase) toUpperCase 如果我们调用对象的Java方法,一切都按预期工作。
user> (. "a" toUpperCase)
"A"

但是,如果我们用返回方法名称的宏调用替换方法名称。
user> (. "a" (m1 toUpperCase))

; Evaluation aborted.
Unable to resolve symbol: toUpperCase in this context

我想使用一些具有像 a().b().c() 这样流畅接口的 Java 库。 在 Clojure 中,这对应为:
(.. obj method1 method2 method3....etc)

我想创建宏来替换这个链中的某些部分,所以我的代码应该是这样的:
(.. obj method1 macro1)

这句话的英译中文是:“这应该扩展到”。
(.. obj method1 method2 method3)

"definline也没有帮助。我也尝试了那个。"
1个回答

6
你遇到这个问题的原因是 . 特殊形式不会按你期望的方式对第二个参数进行求值(指定方法或字段的符号):它将其视为 METHOD m1 的调用,带有 ARGUMENT toUppercase。因此,即使使用宏来指定该参数,也无法动态生成方法的符号作为 .(点)的参数。

解决方法是在宏中包含 .:

 (defmacro m1 [x y] `(. ~x (~y)))
 (m1 "a" toUppercase)
 user> "A"

请注意,您需要在 ~y 周围加上括号,以指示您想调用一个方法而不是读取一个字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接