0

This is only an example, I understand this can easily be achieved with a function.

Don't Work


This is what I've come up with based on the elisp manual and a couple of answers/articles that I have read. The suggestion is to use gensym, but I can't get it to output '("bread"), instead I get '(g719).

(defmacro shop (item) (let ((var (gensym))) `(let ((,var ,item )) (add-to-list 'shopping-list '(,var))))) (let ((item "bread")) (macroexpand '(shop item))) 

RESULTS:

(let ((g719 item)) (add-to-list 'shopping-list '(g719))) 

Works but...


This works when I rename the variable from item to my-item, but I would like to use the same name. I've read you're not suppose to use eval. Not sure about symbol-value?

(defmacro shop (item) `(add-to-list 'shopping-list '(,(symbol-value item)))) (let ((my-item "bread")) (macroexpand '(shop my-item))) 

RESULTS:

(add-to-list 'shopping-list '("bread")) 
0

1 Answer 1

1

Look at the macro expansion again:

(let ((g719 item)) (add-to-list 'shopping-list '(g719))) 

Notice how g719 is inside of a quoted list? It won’t be evaluated there, because it is quoted. Write your macro like this instead:

(defmacro shop (item) (let ((var (gensym))) `(let ((,var ,item )) (add-to-list 'shopping-list (list ,var))))) 

By writing it as a call to the list function, you ensure that the arguments to that call will be evaluated first, and then the value is put into the list instead of the name.

7
  • Thanks for the answer. I copied your code and it does not work. The only difference is it expands to (list g719) instead of '("bread"). Commented Apr 28, 2023 at 17:44
  • That’s what it’s supposed to do. macroexpand doesn’t evaluate anything; that happens later. Commented Apr 28, 2023 at 17:50
  • Sorry about that, you're right. So I noticed that with your answer, I don't even need all the let in the macro or gensym huh? Because it works the same like this in the macro: (backquote (add-to-list 'shopping-list (list ,item))) Commented Apr 28, 2023 at 18:10
  • 1
    Yes. Just be aware that directly substituting an argument multiple times will cause it to be evaluated multiple times. That’s when you need to start using let to collect the value once, and once you do that you want to use gensym in order to avoid shadowing a name that might be in use inside an expression given to you by the caller. Commented Apr 28, 2023 at 18:41
  • What do you mean by substituting an argument multiple times? Do you mean using a comma to sub/evaluate? Commented Apr 28, 2023 at 18:58

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.