More than a week ago, Ian Price wrote: > > Eli, > I'd especially appreciate it if you could clear up any misconceptions I > may have, or may be unintentionally imparting on others.
(And that I'm kind of on the list I can reply...) > * Syntax Parameters > > Syntax parameters[fn:1] are a mechanism for rebinding a macro > definition within the dynamic extent of a macro expansion. It > provides a convenient solution to one of the most common types of > unhygienic macro: those that introduce a special binding each time I'd explicitly say "unhygienic" here rather than "special". > the macro is used. Examples include an 'if' form that binds the > result of the test to an 'it' binding, or class macros that > introduce a special 'self' binding. The `abort' example is also popular, probably even more than `it'. I think that there are practical uses of that (eg, a function with a `return' keyword), whereas anaphoric conditionals are more of an academic exercise that I don't think gets used in practice (at least in Schemes). [As a sidenote, when I worked on that paper I've asked our local Perl guru about the problem of shadowing the implicit `it' in Perl -- he said that in practice it's considered bad style to use it in perl code, and referred me to some book that talks about the pitfalls of using it... I found it amusing that this perl-ism has become such a popular example for unhygienic macros where perl hackers actually try to avoid it.] > With syntax parameters, instead of introducing the binding > unhygienically each time, we instead create one binding for the > keyword, which we can then adjust later when we want the keyword to > have a different meaning. As no new bindings are introduced hygiene > is preserved. This is similar to the dynamic binding mechanisms we > have at run-time like parameters[fn:2] or fluids[fn:3]. An important note to add here is that there is no "dynamic scope" in the usual sense here -- it's rather a dynamic scope during macro expansion, and for macro-bound identifiers. The resulting expanded code is of course as lexical as always. (We've had some discussions at #scheme where this was a confusing point.) > ** define-syntax-parameter keyword transformer [syntax] > Binds keyword to the value obtained by evaluating transformer as a > syntax-parameter. The keyword is bound to the value of the `transformer' expression. (Evaluated at the syntax level, in Racket's case, I don't know if Guile has separate phases yet...) It's not evaluated as a syntax parameter, just like parameters. > The transformer provides the default expansion for the syntax > parameter, and in the absence of syntax-parameterize, is > functionally equivalent to define-syntax. A good note to add here is that it is usually bound to a transformer that throws a syntax error like "`foo' must be used inside a `bar'". It immediately clarifies the use of syntax parameters in the common case. > ** syntax-parameterize ((keyword transformer) ...) exp ... [syntax] > (note, each keyword must be bound to a syntax-parameter > > Adjusts each of the keywords to use the value obtained by evaluating > their respective transformer, in the expansion of the exp forms. It > differs from let-syntax, in that the binding is not shadowed, but > adjusted, and so uses of the keyword in the expansion of exp forms > use the new transformers. A possibly useful analogy is with `fluid-let' which doesn't create new bindings, but rather `set!'s them. But IMO `fluid-let' should die, so using parameters is a better example... -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life!