Jeremy Allen
Jeremy Allen

Reputation: 33

Cannot define functions with my Emacs-Lisp macro

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

Answers (1)

coredump
coredump

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

Related Questions