[plt-scheme] Using previously-defined macros within the "transformer environment"
And just in case you weren't aware, v4.1 has keyword, optional, and
rest arguments built in.
Robby
On Fri, Sep 12, 2008 at 8:18 PM, Matthew Flatt <mflatt 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
>
> In that part of the Guide, the example is a `check-ids' function, but
> the same line of reasoning applies to a macro like `cl-lambda'.
>
> 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.
>
>
> Matthew
>
> _________________________________________________
> For list-related administrative tasks:
> http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
>