Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In clojure, how can I evaluate the arguments to a macro from another macro?

Tags:

macros

clojure

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?

like image 348
Pieter Breed Avatar asked Mar 10 '11 12:03

Pieter Breed


People also ask

What do you mean by passing arguments to a macro?

To assign a macro that you pass arguments to a button, shape, image, or any object, you first right-click that object and click Assign Macro and then type the name of the macro and the argument, following the pattern described in the above examples, and then click OK. 'show_msg "I clicked a button!"'

What is argument macro?

Macro Arguments (DEFINE-! ENDDEFINE command) The macro definition can include macro arguments, which can be assigned specific values in the macro call. There are two types of arguments: keyword and positional. Keyword arguments are assigned names in the macro definition; in the macro call, they are identified by name.

What is the nature of the function argument that are used to create a macro?

Answer: Explanation: To invoke a macro that takes arguments, you write the name of the macro followed by a list of actual arguments in parentheses, separated by commas. The invocation of the macro need not be restricted to a single logical line—it can cross as many lines in the source file as you wish.


1 Answers

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
like image 69
amalloy Avatar answered Oct 03 '22 10:10

amalloy