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.