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.

Original source