getting commas into a macro-defining-macro expansion

From: rif (rif_at_mit.edu)
Date: 05/26/04


Date: 26 May 2004 13:08:31 -0400


I'm trying to write a macro-defining-macro in order to put a nice
facade on top of my CL-to-R gateway. In particular, I'd like to be
able to say
 
(def-r-call r-plot (plot sequence)
  (xlab "") ylab)
 
and have this expand into the following macro definition:
 
(defmacro r-plot (sequence &rest rest &key (xlab "") ylab &allow-other-keys)
  `(r plot ,sequence :xlab ,xlab :ylab ,ylab
                     ,@(remove-plist rest :xlab :ylab)))
 
I'm pretty close, but I can't quite seem to get it. Right now, I have
  
(defmacro def-r-call ((macro-name r-name &rest required-args)
                      &rest keyword-args)
  (let* ((rest-sym (gensym "rest"))
         (keyword-names (mapcar #'atom-or-first keyword-args))
         (keywords (mapcar #'to-keyword keyword-names)))
    `(defmacro ,macro-name (,@required-args
                            &rest ,rest-sym
                            &key ,@keyword-args)
       `(r ,',r-name
           ,@',required-args
           ,@',(mapcan #'(lambda (k n) (list k n))
                       keywords
                       keyword-names)
           (remove-plist ,,rest-sym ,@',keywords)))))

the auxiliary functions are all given at the end of this post
(remove-plist was cribbed from clocc, props to Sam Steingold).
 
The expansion is close to what I want, but clearly not right:
 
CL-USER> (macroexpand-1 '(def-r-call (r-plot plot sequence) (xlab "") ylab))
(DEFMACRO R-PLOT (SEQUENCE &REST #:|rest3667| &KEY (XLAB "") YLAB)
  `(R PLOT
      SEQUENCE
      :XLAB
      XLAB
      :YLAB
      YLAB
      (REMOVE-PLIST ,#:|rest3667| :XLAB :YLAB)))
T
 
The problem I have is getting a list (where the list is bound at
compile-time) to expand into a list of arguments preceded by a comma.
So I don't know how to get ,sequence instead of sequence in the expansion,
and similarly I need
 
:xlab ,xlab :ylab ,ylab
 
instead of
 
:xlab xlab :ylab ylab
 
Any ideas on how to achieve this are appreciated. My knowledge of
nested backquote is sketchy at best --- most of what works above is
from experimentation rather than deep understanding.
 
Cheers,
 
rif

Auxiliary functions used by the def-r-call macro:

(defun atom-or-first (val)
  (if (atom val)
      val
    (car val)))

(defun to-keyword (symbol)
  (intern (symbol-name symbol) :keyword))
                                                                            
(defun remove-plist (plist &rest keys)
  "Remove the keys from the plist.
Useful for re-using the &REST arg after removing some options."
  (do (copy rest)
      ((null (setq rest (nth-value 2 (get-properties plist keys))))
       (nreconc copy plist))
    (do () ((eq plist rest))
      (push (pop plist) copy)
      (push (pop plist) copy))
    (setq plist (cddr plist))))



Relevant Pages

  • Re: Lisp backend protocol
    ... (defun authenticate (address username password) ... "Start the main network loop in a thread" ... (if stream ... (read-sequence sequence stream:end length) ...
    (comp.lang.lisp)
  • Re: combinations not working
    ... (defun prepare-form (sexp) ... 'sequence' can be either a vector or list" ... (check-type sequence (or simple-vector cons)) ...
    (comp.lang.lisp)
  • Re: combinations not working
    ... (defun nrotate (vector start end) ... (defun forall-combinations (vector function) ... 'sequence' can be either a list or vector. ...
    (comp.lang.lisp)
  • combinations not working
    ... (defun nrotate (vector start end) ... (rotatef (aref vector start) ... 'sequence' can be either a list or vector. ...
    (comp.lang.lisp)