Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a Clojure macro to create more than one expression?

Tags:

macros

clojure

Is it possible to write a macro in Clojure that generate more than one value or expression? For me it looks like it's not possible, at least not by using the syntax quote template `(..).

e.g. from: [1 4] via [1 (mr 2 3) 4] to [1 2 3 4]

or from:

(do
  (prn 1)
  (prn 4))

via:

(do
  (prn 1)
  (mr 2 3)
  (prn 4))

to:

(do
  (prn 1)
  (prn 2)
  (prn 3)
  (prn 4))
like image 451
Stefan Avatar asked Sep 21 '10 18:09

Stefan


1 Answers

A macro expands one form into another form, so you can't have a macro return two completely independent forms. However, you can have it return compound forms like do statements that do a bunch of things.

(defmacro foo [n]
  `(do ~@(map #(list println %) n)))

For your example above you can put the macro around the form you wish to modify:

(expand-mr
 (do 
   (prn 1)
   (mr 2 3)
   (prn 4)))

macros are designed to be safe and as such they can't modify anything outside of their own scope. Currently a macro gets an s-expression, and changes it into another more useful or helpful s-expression. In order for a macro to return two separate s-expressions it would have to modify its enclosing expression. The syntax would have to be radically different and I'm not clear how this would be done with s-expressions. The solution of this is to expand the scope of the macro to include everything it needs to modify.

like image 59
Arthur Ulfeldt Avatar answered Nov 07 '22 07:11

Arthur Ulfeldt