This posting will assume that the reader is sufficiently familiar with LISP, to understand how its macros generally work. What such readers will often want to do, is to be able to expand macros, mainly for debugging purposes, before they get compiled into a function. This is because of the fact that, with many LISP implementations, functions are generally compiled in such a way, given actual LISP that acted as source code, and which the macro partially built, that the functions cannot be decompiled, nor the original LISP code recovered from them.
What Common LISP offers, are the functions ‘MACROEXPAND’ and ‘MACROEXPAND-1′, the first of which depends on the second. But, As the Common LISP Hyperspec already points out, ‘MACROEXPAND’ will only keep calling ‘MACROEXPAND-1′, until the second output from this subservient function returns as Nil. This will happen, when the argument is no longer a Macro Form. But, as is already mentioned, this second value output by the subservient function will return as Nil, even if the LISP expression still contains Macro Sub-Forms. And the reason this behaviour can be problematic is the fact that most LISP compilers will keep expanding the Macro Sub-Forms as well, when a macro has been put into a function. This is actually, what makes recursive macros fully possible.
And so, as a better debugging tool, what some LISP programmers might need, is a function that expands all the Macro Sub-Forms as well (even before the macro has been used in a function definition). The following LISP Function accomplishes this:
(defun macroexpand-lists (input) (cond ((null (listp input)) input) ((null input) NIL) ((listp (car input)) (cons (macroexpand-all (car input)) (macroexpand-lists (cdr input)) ) ) (T (cons (car input) (macroexpand-lists (cdr input)) ) ) ) ) (defun macroexpand-all (input) (cond ((null (listp input)) input) ((null input) NIL) (T (let ((expansion1 (macroexpand input))) (cond ((null (listp expansion1)) expansion1) ((eq (car expansion1) 'cl:function) expansion1) ((listp (car expansion1)) (macroexpand-lists expansion1) ) (T (cons (car expansion1) (macroexpand-lists (cdr expansion1)) ) ) ) ) ) ) )
Now, I suppose that what the reader may want to see next could be, how this function of mine performs, if I feed it a LISP Macro, Which I defined in an earlier posting. And the following snip illustrates this. The following snip assumes that the Macro, its subservient Function, and the Macro-Expansion Function were already loaded into a LISP session, as that session was started…
(Updated 7/20/2020, 15h05,,, )