2

I am trying to figure out how to use a macro. I know there are other ways to solve this problem and a macro may or may not be the best answer, but I want to understand the technical problem here vs. solve it some other way.

(setq model-names (list "goat" "alpaca" "llama"))

(defun some-fn (model tag)
  (message "Great news: %s %s" model tag))

(defmacro make-my-defun(model)
  `(defun ,(intern (concat "my-defun-" (eval model))) (tag)
     "Do a thing"
     (interactive "sTag: ")
     (some-fn ,(eval model) tag)))

(macroexpand-1 '(make-my-defun "goat"))
(macroexpand-1 '(make-my-defun (car model-names)))


(cl-loop for name in model-names
         do
;;         (insert (format "%s" name)))
         (make-my-defun name))

This almost works. I get that things passed into a macro are just sexprs, not evaluated code. However, when I try to create these functions in a loop, it simply doesn't work. With the above code...

(make-my-defun "goat")
(make-my-defun (car model-names))

Both of these work. Without the eval it obviously would not work as it would be getting the raw car expr on the second statement.

So what is going on? Why is name a void variable in my cl-loop as far as make-my-defun is concerned? I read the docs on macros and several other resources, but, I am lacking some fundamental insight here.

1 Answer 1

1

cl-loop is ... complicated, but bascially, the name binding inside the loop is done through a cl-symbol-macrolet which expands into code that resolves the binding. There is no way eval can know about this at the time it is called: because (1) you don't want macroexpand to descend into quoted code; (2) you don't want eval to somehow inherit the surrounding lexical environment. When you write (car model-names), it is globally bound.

You already used eval once, I guess you can use it again:

(cl-loop for name in model-names
         do (eval `(make-my-defun ,name)))

But really, macros operate on code, they usually don't evaluate.

Sign up to request clarification or add additional context in comments.

1 Comment

This makes sense. Using macros to template functions just seems like a poor fit for the macro facility. I was able to make this work by essentially doing as you suggested, though I ended up using eval on the results of (macroexpand-1 ..) which was much more of a hack than this. Thanks for the ideas and explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.