What's better about Ruby than Python?
Kenny Tilton
ktilton at nyc.rr.com
Fri Aug 22 00:43:35 EDT 2003
Roy Smith wrote:
> So, is there something else that macros buy you that I'm not seeing?
> People keep talking about how lisp macros are nothing like C/C++ macros.
> OK, I'm willing to be educated. How are they different? Can somebody
> give an example? Keep in mind that the last time I did any serious lisp
> was about 20 years ago.
With the C/C++ preprocessor one is limited to token replacement. I had
great fun with that too. <g> But a Lisp macro is just another function,
one which sees code passed it symbolically and can use all the power of
Lisp to transmogrify it.
This macro just does token replacement:
(defmacro cellify (class-name slot-name)
`(defmethod ,slot-name ((self ,class-name)
&aux (sv (slot-value self ',slot-name)))
(typecase sv
(function (let ((*dependent-cell* sv))
(funcall sv self)))
(otherwise sv))))
OTOH, this next macro destructures something I designed to have the same
syntax as the Lisp DEFCLASS (for familiarity) but adds to it:
(defmacro defmodel (class superclasses (&rest slots))
`(progn
(defclass ,class ,superclasses
,slots)
,@(mapcar (lambda (slot)
(destructuring-bind
(slotname &key initarg accessor)
slot
(declare (ignore slotname initarg))
`(cellify ,class ,accessor)))
slots)))
The mapcar keyword in Lisp iterates over the list of slots and hits each
with the cellify macro (in turn destructuring each slot to get at the
accessor name).
As Mr Reedy demonstrated, this much can also be achieved with
metaclasses, and I in fact converted from macros to metaclasses in Lisp
a few years back. I came back to macros, but only because metaclasses
are not standard in CL and I am in the process of taking my project public.
Here's another example where substitution won't do. I am involved with
some folks putting together Lisp teams to play RoboCup simulation
soccer. One group is doing a straight translation of a C++ team, and
they want to keep it literal so they do not end up rewriting the thing.
Well, the code they are copying uses enum for things like CMD_DASH,
CMD_KICK, etc, and Lisp don't play that. Of course, Lisp handles
symbols, but some of these enums are then used to index into arrays. So
now Lisp need enum:
(defmacro enum (&rest names)
(let ((prior-value -1))
`(progn
,@(mapcan (lambda (name-spec)
(if (consp name-spec)
(destructuring-bind (name &optional
(this-value (incf prior-value)))
name-spec
(prog1 (list
`(defconstant ,name ,this-value)
`(export ',name))
(setf prior-value this-value)))
(list
`(defconstant ,name-spec ,(incf prior-value))
`(export ',name-spec))))
names))))
I need to write code to iterate over a list of names and assign them
numbers. Notice I throw in an export the symbol from the defining
package. Whatever it takes, I can generate that code in a macro and then
any number of enums get ported by deleting the commas (and by changing
midstream changes like "X=42" to (X 42).)
My favorite macro move ever was a problem of deciding how to replicate
coded forms on a remote system by supplying just the arguments supplied
by the author. Once the code runs all slots seem to have been created
equal, but I simply had the DEFPANEL macro note which parameters were
actually typed in (it gets to see the code!) and generated code to stash
a list of the coded names in a dedicate dslot. I loved the elegance of
identifying which arguments had been authored by noting /at compile
time/ which arguments had been authored. :)
--
kenny tilton
clinisys, inc
http://www.tilton-technology.com/
---------------------------------------------------------------
"Career highlights? I had two. I got an intentional walk from
Sandy Koufax and I got out of a rundown against the Mets."
-- Bob Uecker
More information about the Python-list
mailing list