Reputation: 33
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.
Upvotes: 2
Views: 351
Reputation: 38809
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.
Upvotes: 1