pauldoo
pauldoo

Reputation: 18615

Treat Clojure macro as a function

How can I cause a Clojure macro to act as a function, so I can pass it as an argument for example? I would expect to have to wrap it somehow.

I would not expect the wrapped version to behave exactly the same as the original macro (differences of call by name vs call by value), but it would be useful in a few cases where this wasn't important.

Upvotes: 17

Views: 3667

Answers (3)

Alfred Xiao
Alfred Xiao

Reputation: 1788

For the crazy macro make-fn, how about the one below? It should work as well, and hopefully easier to understand.

(defmacro make-fn [m] 
 `(fn [& args#]
    (eval 
      (cons '~m args#))))

Upvotes: 4

trptcolin
trptcolin

Reputation: 2340

If I'm understanding you correctly, you can just wrap it in a function.

Consider this (silly) implementation of a squaring function as a macro:

(defmacro square [x]
  (list * x x))

Passing it directly as an arg won't work, as you know:

user=> (map square [1 2 3 4 5])
java.lang.Exception: Can't take value of a macro: #'user/square (NO_SOURCE_FILE:8)

But wrapping it in a function will do the trick:

user=> (map #(square %) [1 2 3 4 5])
(1 4 9 16 25)

Alternatively (and quite a bit more evil-ly), you could make another macro to do a more generic wrapping:

(defmacro make-fn [m] 
  `(fn [& args#] 
    (eval `(~'~m ~@args#))))

user=> (map (make-fn square) [1 2 3 4 5])
(1 4 9 16 25)

I'd stick with the normal function wrapping, and skip this last hack! :)

Upvotes: 25

jneira
jneira

Reputation: 944

There is a dangerous, deprecated macro that you should not ever use. :-P

http://clojure.github.com/clojure-contrib/apply-macro-api.html

Upvotes: 5

Related Questions