[plt-scheme] Re: Using previously-defined macros within the "transformer environment"
On Sep 12, 9:18 pm, Matthew Flatt <mfl... at cs.utah.edu> wrote:
> At Fri, 12 Sep 2008 08:28:28 -0700 (PDT), "///" wrote:
>
>
>
> > 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).
>
> `require-for-syntax' really is the solution for macros as well as
> functions.
>
> > Has anyone ever done this sort of thing in
> > Scheme before?
>
> A lot, especially in PLT Scheme.
>
> > Is it fixed in a later version of PLT Scheme?
>
> > My ISP is using MzScheme 360.
>
> Version 4.1 offers many improvements, including better documentation.
> In particular, the following part of the current PLT Scheme Guide
> offers an explanation of the problem that you're hitting, along with
> its solution:
>
> http://docs.plt-scheme.org/guide/stx-phases.html
Already been there.
> The essential part of the solution is to put the revised `cl-lambda'
> macro in a module, and then you can use it in run-time expressions by
> `require'ing the module, and you can use it in compile-time expressions
> by using `require' with `for-syntax'.
>
> It's the same in v360, except that `require' with a `for-syntax'
> sub-form is written as a `require-for-syntax' form.
>
I've already been using 'require-for-syntax', but it's kind of funny
when it comes to macros. I've since managed to get my defmacro form to
work from the toplevel (by explicitly expanding the cl-lambda with
expand-once), but I get the same old error message if I use the
defmacro form within a module, even if I import all modules with both
'require' and 'require-for-syntax'.