Thank you to both of you for your detailed responses! I think this is all fascinating.
> On Mar 5, 2018, at 05:18, Ryan Culpepper <ry...@ccs.neu.edu> wrote: > > 1. Yes. To me, at least :) That aspect of hygiene is triggered by a > macro expansion step, and the macro expansion step also defines the > boundary of its effect. In other words, the expansion of a macro > introduces a scope, but syntax classes do not. Compare with the > following examples: Yes, this is what I meant when I wrote that “Syntax classes behave like phase 1 functions, not macros.” It is worth pointing out, however, that not all things that behave like macros are strictly within the realm of the macroexpander — things like match expanders and syntax/parse pattern expanders manually emulate hygienic expansion despite not ever actually yielding to “the” macroexpander. > 2. I think the main technical challenge is finding all of the syntax > objects to flip the scope on, given that syntax classes allow > attributes to have arbitrary values (like opaque structures and > closures), not just syntax objects. We have a similar problem with > syntax properties, which are invisible to the hygiene algorithm. > > It might be easier in a macro system like Andre van Tonder's system, > as Matthew and Sam mentioned. The parallel with syntax properties is a good one, and it’s something that came to mind to me, too. It seems hard to solve in general automatically, but some cooperation from the user might be enough (via some generic protocol like structure type properties). That’s a bit ugly, though. > 3. Maybe. Half-baked musings follow: If these are your half-baked musings, I would like to see what your fully baked ones look like. :) Your points are good ones, and I agree that I have virtually no intuition for which places the boundaries make sense. I will say this, however: while I have developed over the years a reasonably strong intuition for how Racket macros operate, when I was learning the macro system for the first time, I did not find some parts of the hygiene algorithm terribly intuitive. The fact that quoted syntax could be in wildly different lexical contexts but capture and bind the same identifiers because they were in the same dynamic context seemed antithetical to hygiene to me (which I heard described as “respecting the lexical structure of the program as-written”). I find André van Tonder’s system compelling, but I also agree I can’t really evaluate it without trying to write some programs with it. Maybe, with Racket 7, it’d be easier to implement such a macro system in a fork of Racket for experimentation... but the result might be too incompatible with existing code to serve any purpose. It would be an interesting experiment. > On Mar 5, 2018, at 06:45, Matthew Flatt <mfl...@cs.utah.edu> wrote: > > Adding to Ryan's answer, I note that Andre van Tonder's SRFI-72 system > has `quasisyntax` is a primitive. That is, > > #`(x #,y x) > > is not like > > (datum->syntax #'here (list #'x y #'x)) > > because the scope introduced by a `quasisyntax` spans the whole > `quasisyntax` form and causes nested `syntax` forms to not introduce > a fresh scope. Yes, I noticed that, too. My assumption was that a form like with-fresh-renaming-scope would be necessary, but it would be a little bit different from the version originally described. Rather than require it in order to produce distinct scopes from distinct uses of quotation, keep the behavior of the final version of SRFI 72, but allow with-fresh-renaming-scope (or, most likely, something similar but with a more appropriate name) to *weaken*, not strengthen, the hygiene rules. To illustrate, this would lead to the following behavior: (bound-identifier=? #'x #'x) ; ==> #f (with-fresh-renaming-scope (bound-identifier=? #'x #'x)) ; ==> #t If uses of with-fresh-renaming-scope are nested, the outermost use “wins”, yielding the following behavior: (with-fresh-renaming-scope (bound-identifier=? (with-fresh-renaming-scope #'x) (with-fresh-renaming-scope #'x))) ; ==> #t This would allow forms like quasisyntax to introduce with-fresh-renaming-scope in their expansions to avoid distinct uses of syntax from generating distinct identifiers while simultaneously allowing new abstractions to be defined in terms of quasisyntax just as quasisyntax is defined in terms of syntax. Some parts of this are still a little unsatisfying, however. The draft of SRFI 72 you link defines with-fresh-renaming-scope as applying lexically, not dynamically, but it isn’t immediately obvious to me which is the correct behavior in this case. Furthermore, if it applies lexically, what does it mean when with-fresh-renaming-scope is introduced by a macro? If it applies to all identifiers inside its expansion, that feels unhygienic enough to cause trouble... so my own intuition here is nonexistent. As for looking at the discussion, it doesn’t appear to be particularly illustrative. As far as the archives indicate, André himself made the change unprompted, so it’s possible there were some off-list conversations that led to the decision, or he just changed his mind. The only explanation given is “A rationale based on referential transparency is given that this is the right choice.” Anyway, this has all been quite interesting. I’ll think about it, and maybe I’ll play around with an implementation if I get some spare time... though I am running the risk once again of having too many projects and never getting anything done on any of them, so we’ll see. :) Alexis -- 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.