3 ms·
> Macros in CL are just functions that run at compile time Macros work fine in a Common Lisp interpreter at runtime. Here we use an interpreter: Define a mac
by lispm 9y ago
> Macros in CL are just functions that run at compile time
Macros work fine in a Common Lisp interpreter at runtime.
Here we use an interpreter:
Define a macro, which prints a message when it is running.
CL-USER 13 > (defmacro swap (x y)
(print '(> running the swap macro function))
(let ((tmp-sym (gensym)))
`(let ((,tmp-sym ,x))
(setf ,x ,y)
(setf ,y ,tmp-sym))))
SWAP
Use it:
CL-USER 14 > (defun foo (a b)
(let ((a1 a)
(b1 b))
(print (list a1 b1))
(swap a1 b1)
(print (list a1 b1))
(values)))
FOO
The macro function wasn't running, otherwise we had it print something.
Run the code. The macro is run, too.
CL-USER 15 > (foo 20 30)
(20 30)
(> RUNNING THE SWAP MACRO FUNCTION)
(30 20)
Run the code again. The macro is run, too.
CL-USER 16 > (foo 10 40)
(10 40)
(> RUNNING THE SWAP MACRO FUNCTION)
(40 10)
Compile the code, the macro now runs, too.
CL-USER 17 > (compile 'foo)
(> RUNNING THE SWAP MACRO FUNCTION)
FOO
NIL
NIL
In compiled code the macro is no longer needed to run:
CL-USER 18 > (foo 10 40)
(10 40)
(40 10)
Note also what pkhuong said, the SWAP macro will run the place forms twice.
Additionally it's possible to observe the change:
CL-USER 25 > (let ((a (vector 10))
(b (vector 20)))
(swap (aref a (progn (print (list :a a)) 0))
(aref b (progn (print (list :b a)) 0)))
(values a b))
(:A #(10))
(:A #(10))
(:B #(10))
(:B #(20)) ; <- here a is already changed when we get the place value for b
#(20)
#(10)
Common Lisp has a built-in ROTATEF, which takes care of that and which we can use as a replacement for SWAP:
CL-USER 27 > (let ((a (vector 10))
(b (vector 20)))
(rotatef (aref a (progn (print (list :a a)) 0))
(aref b (progn (print (list :b a)) 0)))
(values a b))
(:A #(10)) ; <- only once computed in the first subform to ROTATEF
(:B #(10)) ; <- only once computed in the second subform to ROTATEF
; also the computation of the new value for B does not observe
; the new value of A
#(20)
#(10)
Thus a 'real' SWAP macro will need to look to be different from what the article presents. Otherwise it will not play nicely with the rest of the language: multiple evaluations and side effects are the problems to address.