Consider the following code:
CL-USER> (defmacro sum (a b)
(+ a b))
SUM
CL-USER> (let ((alpha 3) (beta -1))
(sum alpha beta))
; in: LET ((ALPHA 3) (BETA -1))
; (SUM ALPHA BETA)
;
; caught ERROR:
; during macroexpansion of (SUM ALPHA BETA). Use *BREAK-ON-SIGNALS* to intercept.
;
; Argument X is not a NUMBER: ALPHA
; (LET ((ALPHA 3) (BETA -1))
; (SUM ALPHA BETA))
;
; caught STYLE-WARNING:
; The variable ALPHA is defined but never used.
;
; caught STYLE-WARNING:
; The variable BETA is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 2 STYLE-WARNING conditions
; Evaluation aborted on #<SB-INT:COMPILED-PROGRAM-ERROR {10030E4223}>.
There are basically two reasons (that I could think of), which contribute to the failure of this code:
1. The macro sum
is first evaluated upon two variables alpha
and beta
, which are sent as symbols into the macro. So, the code to be evaluated inside the macro is:
(+ 'alpha 'beta)
Which won't work, because we can't add two symbols.
2. The variables alpha
and beta
are lexically bound, because of which, the code of the macro can't access the symbolic values of alpha
and beta
.
Thus, redefining sum
:
CL-USER> (defmacro sum (a b)
(+ (symbol-value a) (symbol-value b)))
WARNING: redefining COMMON-LISP-USER::SUM in DEFMACRO
SUM
Here, the macro sum
will evaluate the value of the symbols provided to it. It can only do it, if it is in the scope of the symbols. So, in order to do that, we can make alpha
and beta
dynamically bound.
Furthermore, in order to check if the dynamic binding is working, we can make a function dynamic-checker
, which is defined below:
CL-USER> (defun dynamic-checker ()
(+ alpha beta))
; in: DEFUN DYNAMIC-CHECKER
; (+ ALPHA BETA)
;
; caught WARNING:
; undefined variable: ALPHA
;
; caught WARNING:
; undefined variable: BETA
;
; compilation unit finished
; Undefined variables:
; ALPHA BETA
; caught 2 WARNING conditions
DYNAMIC-CHECKER
And, finally we can evaluate this code in the REPL:
CL-USER> (let ((alpha 3) (beta -1))
(declare (special alpha))
(declare (special beta))
(print (dynamic-checker))
(sum alpha beta))
Which gives us the error:
; in: LET ((ALPHA 3) (BETA -1))
; (SUM ALPHA BETA)
;
; caught ERROR:
; during macroexpansion of (SUM ALPHA BETA). Use *BREAK-ON-SIGNALS* to intercept.
;
; The variable ALPHA is unbound.
;
; compilation unit finished
; caught 1 ERROR condition
2 ; Evaluation aborted on #<SB-INT:COMPILED-PROGRAM-ERROR {1003F23AD3}>.
CL-USER>
Note the 2
in the end of the error code. This is returned by the function dynamic-checker
, which adds alpha
and beta
, even though they aren't it's parameters, which proves that the variables alpha
and beta
can be accessed dynamically by the members of let
.
Therefore, the macro sum
should've worked now, because both the problems that occurred earlier are resolved.
But this clearly isn't the case, and I'm missing something.
Any help appreciated.
A
andB
in the macro are the symbolsALPHA
andBETA
. Usually macroexpansion will happen at compile time, long before theLET
is evaluated and the bindings established, so the code cannot work. If you use the interpreted mode you might be able to sum theSYMBOL-VALUE
s, but you shouldn't rely on that. – jkiiski