recursive macros are not possible
Imagine you tried that:
(defmacro expand (&rest elements)
(if (not (null (cdr elements)))
`(+ ,(car elements) ,(expand (cdr elements)))
(car elements)))
Now when the macro function is being compiled it expands all macros so it calls (expand (cdr elements))
in it..
(defmacro expand (&rest elements)
(if (not (null (cdr elements)))
`(+ ,(car elements) (+ (cdr elements) (+ (cdr elements) (+ (cdr elements) (+ (cdr elements) ...))))
(car elements)))
Do you see it? Now imagine you instead just expand the first part and not recurse but leave a simpler expression with expand
instead:
(defmacro expand (&rest elements)
(if (not (null (cdr elements)))
`(+ ,(car elements) (expand ,@(cdr elements)))
(car elements)))
This is completely different since the macro never uses the macro directly. However (expand 1 2 3)
expands to (+ 1 (expand 2 3))
and lisp continues to expand the macros until there are none left, leaving (+ 1 (+ 2 3))
without recursion
recursive functions are ok in macros:
(defmacro expand (&rest elements)
(labels ((recfun (elements)
(if (not (null (cdr elements)))
`(+ ,(car elements) ,(recfun (cdr elements)))
(car elements))))
(recfun elements)))
It doesn't need to be a locally defined function either. Usually I implement most of the functionality as a function and make a macro to delay evaluation of some arguments leaving the macro just calling the functions:
(defun make-env-fun (names)
(mapcar (lambda (name) (cons name (symbol-function name))) names))
(defmacro make-env (&rest variables)
`(make-env-fun ',variables))
(make-env cons car cdr)
; ==> ((cons . #<system-function cons>)
; (car . #<system-function car>)
; (cdr . #<system-function cdr>))
So the macro exists since I didn't want to do (make-env 'cons 'car 'cdr)
or (make-env '(cons car cdr))
. The macro only fixes that problem and not the actual work the function is still doing.
So to relate to your problem you want a macro that allows (already-exist symbol ((symbol "bla")))
instead of (already-exist-fun 'symbol '((symbol "bla")))
. Do you see it?
ASSOC
(or(member ... :key #'first)
) to see if the key already exists. – jkiiskiquote
. – user5920214