Actually, what I wrote was wrong. The key piece of information I
overlooked was the following rule:

> A binding for an identifier can only capture a reference to another
> if both were present in the source or introduced during a single
> evaluation of a syntax or quasisyntax form, with the understanding
> that the evaluation of any nested, unquoted syntax or quasisyntax
> forms counts as part of the evaluation of an enclosing quasisyntax.

The key phrase is “single evaluation”, so quote-syntax becomes
generative: multiple evaluations of the same quote-syntax form use
distinct scopes.

This is interesting to me. It’s stricter than Racket’s model for
hygiene, since Racket makes it legal to do things like this:

    (with-syntax ([def #'(define x 42)])
      #'(begin def x))

...which produces a piece of syntax that will evaluate to 42, unlike in
van Tonder’s model, in which it would produce an unbound identifier
error. Of course, this problem is not difficult to solve; it just
requires lifting #'x into a separate binding:

    (with-syntax* ([id #'x]
                   [def #'(define id 42)])
      #'(begin def id))

This model... makes sense to me. I like it. It seems, on the surface,
more intuitive than Racket’s model of introducing fresh scopes in the
expander itself. That said, it’s still quite different from Racket’s
model, so some of what I said in my last message still applies, I think.
I also wouldn’t be surprised if there were some infelicities in the
alternative approach I’m not immediately seeing (corner cases,
perhaps?).

While it’s a bit of a tangent, I’d be quite interested to finding more
information on this alternate model of hygiene from anyone familiar with
the tradeoffs (the SRFI that describes it does not include much in the
way of comparisons). Are there strong reasons to prefer Racket’s model
aside from backwards compatibility and mild convenience when
procedurally assembling pieces of syntax?

> On Mar 4, 2018, at 19:28, Alexis King <lexi.lam...@gmail.com> wrote:
> 
> Sam suggested I take a look at van Tonder’s work as well on Slack, and
> it’s interesting, though it isn’t what I originally had in mind. I
> think it would solve the first example of mine, but it would not solve
> the second. In the second example, all uses of tmp come from the same
> quote-syntax form, merely multiplied via ellipsis. My first mental
> model was to treat syntax classes under ellipses like distinct macro
> invocations, which would require a dynamic, not lexical, treatment of
> scope to be consistent with Racket’s model of hygiene.
> 
> If I’m understanding correctly, attaching fresh scopes at quotation
> rather than expansion treats the source text of the program as the
> ground truth for all scoping information — if two identifiers come
> from the same location in the user’s source code, they can bind each
> other.  This seems like a good model for most things, but it seems
> radically different from Racket’s model when internal definitions are
> involved, since such an interpretation would imply that this program
> should produce a duplicate definition error:
> 
>    (define-syntax-rule (def-x)
>      (define x 42))
> 
>    (def-x)
>    (def-x)
> 
> That seems to me like an enormous break from Racket’s model of
> hygiene, but it doesn’t seem wrong, just different. I could picture a
> different programming language with a different macroexpander using
> such a model successfully. Still, unless I’m misunderstanding the
> implications here, it seems like attaching the scopes at expansion
> (even if “expansion” is really “parsing with syntax classes”) rather
> than quoting would be more consistent with the rest of Racket?

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to