Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make a clojure macro that will allow me to get a list of all functions created by the macro?

I would like to have a macro which I'll call def-foo. Def-foo will create a function, and then will add this function to a set.

So I could call

(def-foo bar ...)

(def-foo baz ...)

And then there would be some set, e.g. all-foos, which I could call:

all-foos
=> #{bar, baz}

Essentially, I'm just trying to avoid repeating myself. I could of course define the functions in the normal way, (defn bar ...) and then write the set manually.

A better alternative, and simpler than the macro idea, would be to do:

(def foos #{(defn bar ...)    (defn baz ...)} )

But I'm still curious as to whether there is a good way for the macro idea to work.

like image 925
Rob Lachlan Avatar asked Jun 01 '10 21:06

Rob Lachlan


1 Answers

Do you want to end up with a set that has the names of functions in it (i.e. a set of Symbols), or a set containing vars (which resolve to functions)? If you want the former, you can add the symbols to an atom in the macro at compile-time, like Greg Harman's version.

If you want the latter, your macro must expand to code that does the atom-swapping after the function is defined. Remember that macros run at compile-time and the macro-expanded result runs at run-time; the function itself is not available until run-time.

(def all-foos (atom #{}))

(defmacro def-foo [x]
  `(let [var# (defn ~x [] (println "I am" '~x))]
     (swap! all-foos conj var#)))

If you want to be able to call the functions in this set, for example, you need to use the latter version.

user> (def-foo foo)
#{#'user/foo}
user> (def-foo bar)
#{#'user/foo #'user/bar}
user> ((first @all-foos))
I am foo
nil
like image 186
Brian Carper Avatar answered Sep 22 '22 20:09

Brian Carper