8
votes

I have two macros. The first one takes a symbol as the only parameter (because it's passed to def, which needs a symbol). The second function takes a list of symbols and should call the first with each symbol individually.

(defmacro m1 [s]
  '(let [f# ... dynamic function definition ...]
      (def ~s f#))

The second macro should take a list of symbols and pass them to the first, but I can't get it to work. The best I could come up with was the following:

(defmacro m2 [symbols]
   `(for [s# ~symbols] (eval (read-string (str "(name.of.current.namespace/m1 " s# ")")))))

which forces the s# to be evaluated before it is passed to the first macro. It is also invoked with a list of strings, rather than a list of symbols.

This is useful for a library which I am using for which all of the functions in the library takes the same two first parameters. I am trying to create wrapper functions, in my namespace, for some of the functions, which automatically provides the first two parameter values which are common to all of them.

Any ideas to improve this?

1
Why a plain fn is not an option here? Something along the lines of (defn m2fun [symbols] (map m1 symbols))skuro
Can you just use partial? I don't really getting what the problem is.nickik

1 Answers

8
votes

Usually when you ask how to get two macros to cooperate, the answer is to not make them both macros. I think my blog post on macro-writing macros will help clarify. For this particular situation I'd probably combine two suggestions from the comments:

(defmacro build-simpler-functions [& names]
  (cons 'do
        (for [name names]
          `(def ~(symbol (str "simple-" name))
             (partial ~name 5 10))))) ; if you always pass 5 and 10

(build-simpler-functions f1 f2)

This expands to

(do
  (def simple-f1 (clojure.core/partial f1 5 10))
  (def simple-f2 (clojure.core/partial f2 5 10)))

which looks like basically what you want.

Edit: if the args you "always" pass are different for each function, you can do this:

(defmacro build-simpler-functions [& names]
  (cons 'do
        (for [[name & args] names]
          `(def ~(symbol (str "simple-" name))
             (partial ~name ~@args)))))

(build-simpler-functions [f1 5 10] [f2 "Yo dawg"]) ; expansion similar to the previous