Hah! You're right. The arrow points to the inner definition. But it's even worse than that---the value comes from the outer definition! At least for `block`, which is what I'm testing with as I haven't copied down your code. Try this:
#lang racket (require racket/block) (define-syntax-rule (m) (displayln 'old)) (let () (block (m)) (define-syntax-rule (m) 'new) (void)) (and with your macro rather than block) On Sunday, June 7, 2020 at 4:27:24 PM UTC-6, Sorawee Porncharoenwase wrote: > > Perhaps I missed something, but the error in the first example is because > there’s no expression at the end of let. If I use this code instead, it > seems to work fine, with the arrow of m pointing to the “new” one. > > (define-syntax-rule (m) 'old) > > (let () > (list+ (m)) > (define-syntax-rule (m) 'new) > (void)) > > The second example perfectly shows why I need > internal-definition-context-track, however. Thank you very much. > > On Sun, Jun 7, 2020 at 7:51 AM Michael Ballantyne <[email protected] > <javascript:>> wrote: > >> > I am unable to come up with a program where this difference is >> significant though >> >> Here's an example: >> >> (define-syntax-rule (m) 'old) >> >> (let () >> ($list >> (m)) >> (define-syntax-rule (m) 'new)) >> >> >> > So I am curious why internal-definition-context-track is needed. >> >> A similar example shows the need here: >> >> ($list >> (define-syntax-rule (m) 5) >> (m)) >> >> Without `internal-definition-context-track` you'll miss the arrow for >> `m`. While `m` does indeed get rebound in the `letrec-syntaxes+values`, >> that binding has an extra scope, so the reference to `m` (recorded in an >> `'origin` property on `5`) doesn't match. >> >> >> >> On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase >> wrote: >>> >>> Thank you so much, Michael! This is very helpful. >>> >>> I can see that when this form is used within another internal definition >>> context, then my version and your version will expand in different order, >>> and I agree that yours makes more sense. I am unable to come up with a >>> program where this difference is significant though (e.g., one fails while >>> the other doesn’t). “so that names bound by later definitions are >>> available” seems to suggest that things like this is not supposed to work >>> on my version: >>> >>> (let () >>> ($list (define (f x) (g x)) >>> (println f)) >>> (define (g x) x) >>> (void)) >>> >>> but it actually does… >>> >>> I also have another question. When should I use >>> internal-definition-context-track? Normally, internal definitions are >>> expanded into letrec-syntaxes+values, so the bindings don’t actually >>> disappear. So I am curious why internal-definition-context-track is >>> needed. >>> >>> Thanks again. >>> >>> On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne <[email protected]> >>> wrote: >>> >>>> Explicitly expanding `e` would ensure that the expansion work only has >>>> to happen once, rather than twice. Even so, the fully-expanded syntax will >>>> be expanded again in `syntax-local-bind-syntaxes` and in the expansion. >>>> >>>> As far as I've seen, the only thing that liberal define contexts >>>> control is whether definitions of functions that accept keyword arguments >>>> expand to a normal `define-values` with runtime handling of keywords, or >>>> expand to a collection of macros and function definitions that allow a >>>> more >>>> efficient calling convention for first-order calls. The latter expansion >>>> doesn't work for contexts like `class` where function definitions are >>>> re-interpreted in a way that adds indirection, so it is only enabled in >>>> contexts that opt-in. >>>> >>>> I see more bug in your macro: as its very first task, it should check >>>> if `(syntax-local-context)` is `'expression`. If not, it should expand to >>>> `(#%expression <the-original-call>)`. This ensures that its expansion is >>>> delayed until the second pass of the surrounding definition context so >>>> that >>>> names bound by later definitions are available. >>>> >>>> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase >>>> wrote: >>>>> >>>>> Ah, apparently I need syntax-local-identifier-as-binding. Here’s a >>>>> revised code that passes the tests. >>>>> >>>>> (begin-for-syntax >>>>> (define ((do-it gs ctx) e) >>>>> (let loop ([e e]) >>>>> (define e-expanded (local-expand e >>>>> (list gs) >>>>> (list #'begin >>>>> #'define-syntaxes >>>>> #'define-values) >>>>> ctx)) >>>>> (syntax-parse e-expanded >>>>> #:literals (begin define-syntaxes define-values) >>>>> [(begin body ...) #`(begin #,@(map loop (attribute body)))] >>>>> [(define-values (x ...) e) >>>>> #:with (x* ...) (map syntax-local-identifier-as-binding >>>>> (attribute x)) >>>>> (syntax-local-bind-syntaxes (attribute x) #f ctx) >>>>> #'(define-values (x* ...) e)] >>>>> [(define-syntaxes (x ...) e) >>>>> #:with (x* ...) (map syntax-local-identifier-as-binding >>>>> (attribute x)) >>>>> (syntax-local-bind-syntaxes (attribute x) #'e ctx) >>>>> #'(define-syntaxes (x* ...) e)] >>>>> [e #'(set! acc (cons e acc))])))) >>>>> >>>>> Still not sure if there’s still anything wrong. In particular, do I >>>>> need to expand e in define-syntaxes? And do I need to use >>>>> prop:liberal-define-context for gs? (I don’t understand what liberal >>>>> expansion is even after reading the docs several times) Both of these are >>>>> done in the implementation of block, but without them, it seems to >>>>> work equally well. >>>>> >>>>> On Fri, Jun 5, 2020 at 6:30 PM Sorawee Porncharoenwase < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Racketeers, >>>>>> >>>>>> I’m creating a macro that collects values in the internal-definition >>>>>> context. E.g., >>>>>> >>>>>> ($list >>>>>> 1 >>>>>> (define x 2) >>>>>> x) >>>>>> >>>>>> should evaluate to '(1 2). >>>>>> >>>>>> Here’s my implementation, and it kinda works: >>>>>> >>>>>> #lang racket >>>>>> >>>>>> (begin-for-syntax >>>>>> (define ((do-it gs ctx) e) >>>>>> (let loop ([e e]) >>>>>> (define e-expanded (local-expand e (list gs) #f ctx)) >>>>>> (syntax-case e-expanded (begin define-syntaxes define-values) >>>>>> [(begin body ...) >>>>>> #`(begin #,@(map loop (syntax->list #'(body ...))))] >>>>>> [(define-values ids e) >>>>>> (begin >>>>>> (syntax-local-bind-syntaxes (syntax->list #'ids) #f ctx) >>>>>> e-expanded)] >>>>>> [(define-syntaxes ids e) >>>>>> (begin >>>>>> (syntax-local-bind-syntaxes (syntax->list #'ids) #'e ctx) >>>>>> #'(begin))] >>>>>> [e #'(set! acc (cons e acc))])))) >>>>>> >>>>>> (define-syntax ($list stx) >>>>>> (define gs (gensym)) >>>>>> (define ctx (syntax-local-make-definition-context)) >>>>>> (syntax-case stx () >>>>>> [(_ body ...) >>>>>> #`(let ([acc '()]) >>>>>> #,@(map (do-it gs ctx) (syntax->list #'(body ...))) >>>>>> (reverse acc))])) >>>>>> >>>>>> ($list 1 >>>>>> (define x 2) >>>>>> x) >>>>>> >>>>>> There are problems though. If I change define to define2 as follows: >>>>>> >>>>>> (define-syntax-rule (define2 x y) >>>>>> (define-values (x) y)) >>>>>> >>>>>> ($list 1 >>>>>> (define2 x 2) >>>>>> x) >>>>>> >>>>>> Then I get the “identifier used out of context” error. This doesn’t >>>>>> make sense to me at all. My define2 should be very similar to define… >>>>>> >>>>>> There’s also another weird problem: >>>>>> >>>>>> ($list 1 >>>>>> (define-syntax (x stx) #'2) >>>>>> x) >>>>>> >>>>>> The above works perfectly, but by wrapping x with #%expression, I >>>>>> get the “identifier used out of context” error again. >>>>>> >>>>>> ($list 1 >>>>>> (define-syntax (x stx) #'2) >>>>>> (#%expression x)) >>>>>> >>>>>> What did I do wrong? >>>>>> >>>>>> Thanks! >>>>>> >>>>> -- >>>> 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 [email protected]. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/racket-users/748eead8-76b9-43bc-94da-2c832ba8896do%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/racket-users/748eead8-76b9-43bc-94da-2c832ba8896do%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >> 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 [email protected] <javascript:>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/racket-users/ae981bda-94d3-43d2-ae23-a41f5160aa0ao%40googlegroups.com >> >> <https://groups.google.com/d/msgid/racket-users/ae981bda-94d3-43d2-ae23-a41f5160aa0ao%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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 [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/30972297-14f6-4cf9-8821-de5753f3dacfo%40googlegroups.com.

