Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure evaluation of macros

Tags:

macros

clojure

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

like image 395
Vitomir Kovanovic Avatar asked Mar 26 '11 20:03

Vitomir Kovanovic


People also ask

How do you evaluate in Clojure?

Both the operator and the operands (if any) are evaluated, from left to right. The result of the evaluation of the operator is cast to IFn (the interface representing Clojure functions), and invoke() is called on it, passing the evaluated arguments. The return value of invoke() is the value of the call expression.

Does Clojure have macros?

Clojure has a programmatic macro system which allows the compiler to be extended by user code. Macros can be used to define syntactic constructs which would require primitives or built-in support in other languages. Many core constructs of Clojure are not, in fact, primitives, but are normal macros.

What is clojure form?

Clojure (/ˈkloʊʒər/, like closure) is a dynamic and functional dialect of the Lisp programming language on the Java platform. Like other Lisp dialects, Clojure treats code as data and has a Lisp macro system.


1 Answers

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.

like image 92
Joost Diepenmaat Avatar answered Sep 26 '22 00:09

Joost Diepenmaat