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

Writing macros within macros :Part II, almost there



    Date: Fri, 22 Dec 89 14:17:51 MST
    From: intvax!gnome!drstrip@unmvax.cs.unm.edu (David R. Strip)

    I have gotten this far:

    (defun keyword-pairs (fields)
      (let ((output ()))
	(dolist (x fields output)
	  (setq output (cons (intern (string x)) output))
	  (setq output (cons (intern (concatenate 'string ":" (string x))) output)))))

[This second produces |:FOO| instead of :FOO; if you want the latter
(which you do in this case), you must use
   (intern (string X) "Keyword")
or equivalent.  Under Genera, the keyword package can be found in the
variable SYS:PKG-KEYWORD-PACKAGE.] 

    (defmacro def-geo-thing (name &rest fields)
      (let ((conc-name (intern (concatenate 'string "MAKE-" (string name)))))
      `(progn
	 (defflavor ,name
		 ,fields
		 ()
	   :initable-instance-variables
	   (:constructor ,conc-name)
	   )
	 (defmacro ,name (id ,@fields)
	 `(setq ,id (,',conc-name ,',@(keyword-pairs fields)))))))

    (def-geo-thing circle center radius plane)

;;; Here's my version:
(defmacro def-geo-thing (name &rest fields)
  (let ((constructor (intern (format nil "~A-~A" name 'maker))))
    `(progn
       (defflavor ,name ,fields ()
	 :initable-instance-variables
	 (:constructor ,constructor))
       (defmacro ,name (ID ,@fields)
	 `(setf ,ID (,',constructor ,,@(mapcan (lambda (field-name)
						  `(',(intern (string field-name) "Keyword")
						    ,field-name))
						fields)))))))

(def-geo-thing circle center radius plane) ==>
(PROGN
  (DEFFLAVOR CIRCLE (CENTER RADIUS PLANE) NIL :INITABLE-INSTANCE-VARIABLES
	     (:CONSTRUCTOR CIRCLE-MAKER))
  (DEFMACRO CIRCLE (ID CENTER RADIUS PLANE)
    `(SETF ,ID (CIRCLE-MAKER :CENTER ,CENTER :RADIUS ,RADIUS :PLANE ,PLANE))))

Unfortunately, while I have a lot of experience at debugging these kinds
of things, I don't have a good theoretical framework which tells me what
the right way to do this is.  I basically re-do my macroexpansion over
and over until it works.  I have a number of things which I have figured
out to try; these include:

  ,', -- delays evaluation one time
  ,,  -- evaluate something in the next environment up
  ,,@ -- same, but conses the result in at this point
  `', -- quote the thing which follows

Absolutely the only way to really get good at this is to write a bunch
of macro-writing macros.  If you have a complete who-calls database, try
editing the callers of DEFMACRO; I warn you, though, that many of those
macro-writing macros are quite old and use ancient technology.