The big difference between macros in C, and macros in Lisp (one that was not touched upon in the artice) is that in Lisp, there is absolutely no difference between a function and a macro except for the fact that functions are executed at runtime and macros are executed at compile time.
What this means is that a Lisp macro can perform IO, computations, call other functions, call other macros, receive variables etc. Everything that a function can do, except that this is done at compile time.
An example of a Lisp macro that I find useful: In OpenGL, glPushMatrix() and glPopMatrix() are called all the time.
A simple Lisp macro extends the language:
(defmacro with-glPushMatrix (&body body)
`(progn
(glPushMatrix)
(unwind-protect
(progn ,@body)
(glPopMatrix))))
to allow this...
(defun draw-objects ()
(with-glPushMatrix
(glRotatef *view_rotx* 0.0 1.0 0.0)
(glRotatef *view_roty* 1.0 0.0 0.0)
(glRotatef *view_rotz* 0.0 0.0 1.0)
(with-glPushMatrix
(glTranslatef (- 3.0) (- 2.0) 0.0)
(glRotatef *angle* 0.0 0.0 1.0)
(glCallList *gear1*))
(with-glPushMatrix
(glTranslatef 3.1 (- 2.0) 0.0)
(glRotatef *angle* 0.0 0.0 1.0)
(glCallList *gear2*))
(with-glPushMatrix
(glTranslatef (- 3.1) 4.2 0.0)
(glRotatef *angle* 0.0 0.0 1.0)
(glCallList *gear3*))))
All code within with-glPushMatrix is automatically wrapped between glPushMatrix() and glPopMatrix() calls. These calls can even be nested with glPopMatrix() being called correctly on the way out, eliminating the bug of not matching a push with a pop.
Also, everything is automatically indented allowing for easy reading of the code.
This shows one of Lisps greatest strengths: In other languages, e.g. C/C++, the problem is broken down into smaller and smaller pieces until it can be implemented in code. In Lisp, the language is extended and brought UP to the problem domain. The language is made to fit the problem.
-Luke
[edited by - HairyTroll on June 24, 2003 7:06:09 PM]
[edited by - HairyTroll on June 24, 2003 7:11:35 PM]
|