Common Lisp: Passing Symbol to Macro
arguments, common-lisp, macros, metaprogramming, symbols
Solution
`'a` is shorthand for `(quote a)`, which is the list that you're passing to your macro. Macro arguments are not evaluated, but passed as is. When used as an argument to a function (i.e., not to a macro) `(quote a)` is evaluated first, and the result of evaluating `(quote a)` is the symbol `a`. Consider, for instance, the difference between
(list 'a) ===
(list (quote a))
; => (a)
and
'('a) ===
'((quote a)) ===
(quote ((quote a)))
; => ((quote a)) ;; which may also be printed ('a)
An example of using a symbol argument to a macro
Based on a request in the comments, here's a `defstruct`-like macro that creates some functions that incorporate the name of the structure.
(defmacro my-defstruct (name slot)
"A very poor implementation of defstruct for structures
that have exactly one slot"
(let ((struct-name (string name))
(slot-name (string slot)))
`(progn
(defun ,(intern (concatenate 'string (string '#:make-) struct-name)) (value)
(list value))
(defun ,(intern (concatenate 'string (string struct-name) "-" slot-name)) (structure)
(car structure)))))
Here's what, e.g., `(my-defstruct foo bar)` expands to:
CL-USER> (pprint (macroexpand '(my-defstruct foo bar)))
(PROGN
(DEFUN MAKE-FOO (VALUE) (LIST VALUE))
(DEFUN FOO-BAR (STRUCTURE) (CAR STRUCTURE)))
Examples of use:
CL-USER> (my-defstruct foo bar)
FOO-BAR
CL-USER> (make-foo 34)
(34)
CL-USER> (foo-bar (make-foo 34))
34
Problem
The purpose of this macro is to create a macro that gives a name to accessing a certain key of an associated list. ``` (defmacro generate-accessor (key-symbol prefix) (let ((mac-name (intern (string-upcase (concatenate 'string prefix "-" (string key-symbol)))))) `(defmacro ,mac-name (alis) `(assoc ,',key-symbol ,alis)))) ``` So when I try it - ``` CL-USER> (generate-accessor 'a "alist") ; ERROR> 'A cannot be coerced to a string. ``` and yet... ``` CL-USER> (string 'a) ; RESULT> "A" ``` So I try again using SYMBOL-NAME to coerce the symbol into a string ``` (defmacro generate-accessor (key-symbol prefix) (let ((mac-name (intern (string-upcase (concatenate 'string prefix "-" (symbol-name key-symbol)))))) `(defmacro ,mac-name (alis) `(assoc ,',key-symbol ,alis)))) ``` This time when I try it - ``` CL-USER> (generate-accessor 'a "alist") ; ERROR> The value 'A is not of type SYMBOL. ``` and yet... ``` CL-USER> (symbol-name 'a) ; RESULT>"A" CL-USER> (symbolp 'a) ; RESULT>T ``` Whenever I use `'a` outside of my macro, it gets automatically interned as a symbol like I expect. Yet somehow when I pass `'a` to my macro, it arrives as a quoted chunk. I don't understand why it isn't being evaluated, especially at a point before the backquote begins. I know I am not understanding something fundamental to Lisp but I don't know how to see it right now.