[plt-scheme] Using previously-defined macros within the "transformer environment"

From: /// (84jkdl202 at sneakemail.com)
Date: Fri Sep 12 11:28:28 EDT 2008

I'm using PLT Scheme to write a Web site. In order to make PLT Scheme
more usable (that is, more like Common Lisp), I've been spending some
time writing a few macros. First, I wrote a new version of the
"lambda" form. It's just like the original lambda, except it
understands &OPTIONAL, &KEY, and &REST, like Common Lisp (&KEY is
especially important). It was a first step in porting some of my CL
code over to Scheme.

Next, I decided to try to write a DEFMACRO form that understands the
same sort of lambda-list. (PLT is generous enough to provide "define-
macro", but macros defined this way can only have Scheme lambda-lists,
and the macros I'm trying to port rely heavily on &KEY-- a simple dot
will not do!) The easiest way to do this would be to use the LAMBDA
macro I previously wrote, so that the macro-expansion invokes the
LAMBDA macro and automatically inherits its lambda-list processing
capabilities. Unfortunately, it turns out that my LAMBDA macro is not
visible in the transformer environment, even though I used (require-
for-syntax cl-lambda) to import the module that defines it. I would
hate to have to copy and paste the source for the LAMBDA form (and all
the local functions it depends on) to get my DEFMACRO form to work,
but at the moment it looks like that's what you have to do to satisfy
the Hygienic Macro System. I tried to solve the problem with Google
(which has helped on countless occasions), but apparently nobody has
ever tried to use one macro to expand another in Scheme.

Here's what the defmacro macro looks like:

(define-macro (defmacro name lambda-list . body)
	  (let* ((rest-arg (gensym))
		 (simple-lambda-list (make-simple-lambda-list
					    (fold-optional-args-into-rest lambda-list rest-arg))))
	    `(define-macro ,(cons name simple-lambda-list)
	       (apply (cl-lambda ,lambda-list , at body)
		      ,(cons-to-rest-arg-if-necessary simple-lambda-list rest-
arg)))))

"simple-lambda-list" converts a CL lambda-list into a Scheme one
(including that
stupid little dot), while "fold-optional-args-into-rest" removes all
&OPTIONAL and
&KEY arguments and adds a &REST argument to replace them (and also
replaces
any user-provided &REST arguments with its own definition).
(foo bar &optional baz &rest haha) becomes (foo bar &rest g39).

It expands as expected: (defmacro foobar (x &optional y)
`(list ,x ,y)) expands into:

(define-macro (foobar x . g73)
  (apply (cl-lambda (x &optional y) (quasiquote (list (unquote x)
(unquote y))))
	 (cons x g73)))

However, the above macro can't be expanded any further because:

  reference to undefined identifier: cl-lambda

I know the problem is caused by the transformer environment because
the cl-lambda form works from the REPL. In fact, if you define x and
g73 in a let form and paste in the definition of the above macro, you
get the expansion that should result from the macro:

(let ((x 1)
      (g73 '(2)))
    (apply (cl-lambda (x &optional y) (quasiquote (list (unquote x)
(unquote y))))
	 (cons x g73)))

==> (list 1 2)

define-for-syntax allows you to define functions in the transformer
environment, but there is no such thing as define-macro-for-syntax, or
even define-syntax-for-syntax. The PLT Scheme reference manual is
absolutely silent on this issue, except that it seems to suggest
(incorrectly) that require-for-syntax should solve the problem (it
only helps with functions). Has anyone ever done this sort of thing in
Scheme before? Is it fixed in a later version of PLT Scheme?

My ISP is using MzScheme 360.


Posted on the users mailing list.