[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to write macro within macro



    Date: Fri, 22 Dec 89 19:42:37 EST
    From: barmar@Think.COM

    Well, Kent and I both made the same mistake in our versions with nested
    backquotes ... I'm not sure there's a way to do this using nested backquotes.

I had spoken to him on the phone later about this and straightened this out.
In order to reduce spurious mail traffic, I wasn't going to bother anyone with
further mail unless someone asked for it specifically.  I guess your message 
counts.

It is indeed possible to win here using backquote.  The answer involves using
the ,,@ trick alluded to in my explanatory text:

 (defmacro def-thing (name &rest ivs)
   (let ((maker (intern (format nil "MAKE-~A" name)))
	 (id (make-symbol "ID")))
     `(progn (defflavor ,name ,ivs () 
	       :initable-instance-variables 
	       (:constructor ,maker))
	     (defmacro ,name (,id ,@ivs)
	       `(setq ,,id
		      (,',maker
		       ;This is the fixed line:
		       ,,@(mapcan #'(lambda (x) 
				       (list (intern (string x) (find-package "KEYWORD"))
					     x))
				   ivs))))
	     ',name)))

By the way, this solution shows a form like the following in a DEF-THING
expansion:
 (MAKE-FOO ,:A ,A ,:B ,B ...)
Some people don't like the ,:A even though it is technically harmless
since :A will self-evaluate.  Making it go away is straightforward--you
just introduce an additional quote as shown here:

 (defmacro def-thing (name &rest ivs)
   (let ((maker (intern (format nil "MAKE-~A" name)))
	 (id (make-symbol "ID")))
     `(progn (defflavor ,name ,ivs () 
	       :initable-instance-variables 
	       (:constructor ,maker))
	     (defmacro ,name (,id ,@ivs)
	       `(setq ,,id
		      (,',maker
		       ;This is the old fixed line:
		       ,,@(mapcan #'(lambda (x) 
				       ;This is the additional fix:
				       (list `',(intern (string x)
					        (find-package "KEYWORD"))
					     x))
				   ivs))))
	     ',name)))

This will make that list in question come out as:
 (MAKE-FOO :A ,A :B ,B ...)
[In fact, I believe it comes out as 
 (MAKE-FOO ,':A ,A ,':B ,B ...)
but either the printer optimizes the display or else the backquote
stuff actually removes it.  Either way, it's semantically equivalent
because the thing following the ,' can be proven to be a constant.]

  [Barmar again:]
    By the way, there is a different, minor error in Kent's second version.
    The LIST* should be LIST (the ",@" takes care of splicing into the list
    properly).

Right. Thanks for noting this.