简体   繁体   中英

Clojure evaluation of macros

I have a problem constructing a DSL in Clojure. This is the concrete problem I have isolated from everything else.

Let's say we hava a simple macro:

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

it just returns the literal supplied user> (m1 toUpperCase) toUpperCase

if we call java method for object everything works as expected

user> (. "a" toUpperCase)
"A"

but if we substitute method name for macro call that returns the methodname

user> (. "a" (m1 toUpperCase))

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

I want to use some java library that has fluent interface like a().b().c(). This maps to Clojure as:

(.. obj method1 method2 method3....etc)

I want to create macros that substitute some parts of this chain so my code should be like:

(.. obj method1 macro1)

and that should expand to

(.. obj method1 method2 method3)

definline also doesn't help. I tried that also

The reason you're running into this problem is that the . special form does not evaluate its second argument (the symbol specifying the method or field) in the way you expect: it sees it as a call of the METHOD m1, with the ARGUMENT toUppercase. Because of that, you cannot generate the symbol for the method dynamically just as an argument to . (dot) - even if you use a macro to specify that argument.

A way to work around that is to include the . in your macro:

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

Note that you need to wrap parentheses around ~y to indicate you want to call a method instead of reading a field.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM