On 6/7/20 9:23 PM, Alexis King wrote:
>     #lang racket
>     (define-syntax-rule (m) (displayln 'old))
>     (let ()
>       (m)
>       (define-syntax-rule (m) 'new)
>       (void))

I think you meant:

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

which prints:

old
new

And as usual, Alexis points right to the heart of the problem. All the
way back in Dybvig's psyntax expander, definition contexts are partially
expanded to uncover definitions, and then fully expanded in a second
step. Flatt's papers dig deeper (I hope he is reading this thread). I
will quote one thing directly from Alexis, "resolution of macro bindings
also involves a /temporal/ component, since the compile-time binding
table evolves as the program is expanded."

I'd love to hear your idea of a satisfying semantics to aim for, even if
it doesn't match scheme/racket historical semantics. In the meantime,
I'll draw your attention to another community which has evolved a
potential solution to the "hopeless top level":

Nix is a lazy functional language which is primarily used to define
binding contexts--very much like our "hopeless" definition
contexts--primarily for unix package configuration. The concept of an
"overlay" has emerged (this term might be overloaded in Nix).

An overlay represent a step in the fixed point definition of a binding
context.

Recall the Alexis quote, "resolution of ... bindings ... involves a
/temporal/ component," well in Nix an overlay is a step in the fixed
point definition of a binding context.

It probably isn't proper to call this "temporal", but it is a sequence
of definition contexts which lead to the ultimate desired set of
definitions (the "fixed point" of the computation).

As a racket procedure, an overlay would be defined something like this:

(define (overlay self super) ...etc...)

Overlay is a function ("macro"). It takes two sets of bindings, and
produces a third. Self and super are the conventional names (not great
names) for the parameters.

In the overlay system, a binding context is defined by chaining together
a bunch of overlays. Something like this:

(letrec ((super0 (combine initial (overlay0 self initial)))
         (super1 (combine super0 (overlay1 self super0)))
         (super2 (combine super1 (overlay2 self super1)))
         ;; etc...
         (final superN))
  ;; "self" is the desired binding context.
  ;; "superX" are the staged binding contexts along the way.
  self)

Now of course just like with macros, there can be overlay producing
overlays etc. If you look at an overlay as a macro, it has simultaneous
access to the entire structure of the  of the bindings via the two
handles, self and super, together with whatever bindings are stashed
away by other overlays. You could imagine a sequence of bindings
contexts in which one definition of cc, compiles the next, bootstrapping
a compiler from its initial version, for example, or even one version of
an overlay bootstrapping another overlay.

There are conventions making use of self and super when writing an
overlay. You, and your downstream peers in the chain, will be overriding
the ones in super, if you provide something from self, you know it is
the stable final result.

Isn't there some solid semantics for a hopeful top level in this idea?

-- 
Anthony Carrico

-- 
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/ba63f17b-366a-d87e-b1f4-9009952bd805%40memebeam.org.

Reply via email to