> On Jun 7, 2020, at 17:44, Sorawee Porncharoenwase <sorawee.pw...@gmail.com> 
> wrote:
> 
> Wow, so block is currently buggy?!
> 

This issue isn’t with `block`, per se (though `block` could cooperate more 
nicely with definition context expansion to avoid this problem). You can 
reproduce it without any first-class definition contexts at all:

    #lang racket
    (define-syntax-rule (m) (displayln 'old))
    (let ()
      (m)
      (define-syntax-rule (m) 'new)
      (void))

Arguably, the real issue is the mechanism behind Check Syntax. Check Syntax 
collects information about uses and bindings from the fully-expanded program, 
but that is not straightforward for macro uses and local macro bindings, since 
those go away after expansion. So the expander annotates the program with 
information about disappeared identifier uses and disappeared local bindings 
using the 'origin, 'disappeared-use, and 'disappeared-binding syntax properties.

The hope is that the binding structure of the source program can be 
reconstructed from the fully-expanded program by inspecting identifiers’ 
scopes. This seems plausible, since the scopes of a fully-expanded program 
dictate the binding structure of runtime variables by definition. However, this 
example reveals a flaw in that logic: resolution of macro bindings also 
involves a temporal component, since the compile-time binding table evolves as 
the program is expanded.

Frankly, this temporal dependency is unsatisfying. For runtime bindings, we 
enjoy predictable recursive definition contexts and inter-module lexical 
binding, courtesy of the module system. But to paraphrase Matthew, resolution 
of compile-time bindings is “distressingly like the top level,” since it 
requires interleaving of expansion and evaluation in a similar way.

I think this suggests that perhaps there is something fundamentally incomplete 
in our model of macroexpansion. However, it seems impossible to solve this 
problem without somehow restricting the macro language: the status quo allows 
macros to both (a) expand to absolutely anything via arbitrary procedural logic 
and (b) perform arbitrary side-effects, which allows them to observe expansion 
order. A more restrictive model could require macros to declare more 
information up front (which would allow the macroexpander to learn more about 
the binding structure of a program without fully expanding macros) or could 
provide access to state through restricted channels in such a way that the 
expander could “speculatively” expand a macro, then go back later and change 
its mind.

Of course, these would both require radical, deeply incompatible changes to the 
Racket macro system, so I do not expect them to actually be implemented! But 
perhaps they can be food for thought.

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.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/D48BCCBB-AE1F-47CC-93E8-B90D1129E169%40gmail.com.

Reply via email to