Comment 5 for bug 225387

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote : Re: [Bug 225387] Re: add something like plt's syntax-local-value

On May 6, 2008, at 3:13 AM, Stephen Wrobleski wrote:
> It looks like my email reply to <email address hidden> didn't
> make it
> here even though I didn't get an error.
>
> Explicit expansion is the obvious case of something you can't do
> under r6rs
> (+ikarus) that would be enabled
>
> ; "expands" the outer level of the given expression
> ; 1. assumes the first element is a syntactical keyword
> ; 2. does not deal with expansions of the other elements, nested
> forms, or a
> ; new returned syntax form
>
> (define (expand-outer stx)
> (syntax-case stx ()
> [(id etc ...)
> ((syntax-local-value #'id) stx)]))

This will not work in general for all keyword-bound identifiers
for two reasons:

1. You are collapsing two macro expansion steps into one. This
will cause incorrect (and often insidious) hygiene problems in
the mark/antimark algorithm.

2. Not all syntaxes are bound to procedures so you cannot just
call the value.

> Fixing the restrictions in the example would create a full-
> functional explicit
> expansion mechanism. Such explicit subexpansion would be necessary to
> implement functionality similar to the local defines of let and
> lambda.
>
> (define-syntax define-five
> (syntax-rules (define-five)
> [(define-five id)
> (define id 5)]))
>
> ; evaluates to 5
> (let ()
> (define-five vv)
> vv)
>
> a user-defined 'let' can only know what to do with define-five
> after it
> explicitly expands and sees that it's a define clause (rather than an
> expression)

Hmmm. I'm not sure I understand here.

A user-define let in terms of lambda would not have to know about
define-five. Just try it:

 > (let-syntax ([let
                 (syntax-rules ()
                   [(_ ([x v] ...) b b* ...)
                    ((lambda (x ...) b b* ...) v ...)])])
     (let ()
       (define-syntax define-five
         (syntax-rules ()
           [(_ id) (define id 5)]))
       (define-five vv)
       vv))
5

If what you want is actually implement full internal defines, that
would require me to expose all of the expander's internals and you
would have to know how to handle each and every form the expander
may throw at you. Neither you nor I would want to do this. Since
lambda already has an internal defines context in its body, you can
just use that.

> Imagine a 'class' syntax definition, which uses two keywords
> 'method' and
> 'field'. The keywords are defined to raise an error, and the
> 'class' expander
> does a free-identifier=? to test for their usage.

Like quasiquote recognizing unquote and unquote-splicing (each of
which raises a syntax error), right?

> To be able to create a new definition on top of that library
> (without touching the
> library itself), the class macro must explicitly pre-expand forms
> so that it
> can check for returned method and field forms.

Well, that's not how I'd do it. I'd just let it fail and the
syntax error trace would show the original offender.

> There are cases where I would like to be able to check for the
> presence of a
> syntactical definition rather than blindly expanding, which is why
> I see
> syntax-local-value as more useful than a generic expand.

localexpand, macroexpand, macroexpand1, or whatever procedure
that allows a transformer to fully or partially expand its input
are not in the Ikarus macro expansion model and it's unlikely
that they will be wedged in.

> For the case of arbitrary values being passed around at expansion
> time as
> syntactical keywords, think of the r6rs syntactic record layer. When
> defining a record, a syntactical definition is created for the
> 'type', which
> is used by further macros to influence the code they generate. I'd
> like that
> generalized capability to use in my own code.

This, I agree, is useful. There should be a way to inject
arbitrary values into the compile time environment and retrieve
them at later times. All other compile-time values (e.g., lexical
variables, transformers, record type identifiers, enumeration
types, module names, primitive keywords, etc. etc.) will not be
exposed to the user though. So, if you put a value in, you can
get it out, and nothing more.

I know this sounds like it won't be fulfilling all your needs,
but this is what I'm offering right now. How does it sound?

Aziz,,,