Question about syntax-local-lift-require


The documentation of syntax-local-lift-require says

If raw-require-spec and stx are part of the input to a transformer, then typically syntax-local-introduce should be applied to each before passing them to syntax-local-lift-require, and then syntax-local-introduce should be applied to the result of syntax-local-lift-require. Otherwise, marks added by the macro expander can prevent access to the new imports.

But the two applications of syntax-local-introduce to stx will just cancel each other, so what's the purpose of applying syntax-local-introduce to stx?

In the interval between the two points in time, the expander views potential identifiers as "syntax-locally-introduced” and acts accordingly. But that’s of course not the reality. So at the end, your macro removes these scopes again to set up the proper bindings.

Perhaps it was necesary when syntax marks were not conmutative??

What does it mean for syntax marks to be noncommutative?

I see your point. Except as the function description says (and I checked the function's source code to confirm), all syntax-local-lift-require does is (1) do a require lift, which does not use stx in anyway, and (2) add a scope to stx and return it. So it doesn't matter if stx is "syntax-locally-introduced” or not within syntax-local-lift-require.

For example in this program:

#lang racket

(define id #'hello)

(define mark1 (make-syntax-introducer))
(define mark2 (make-syntax-introducer))

(bound-identifier=? (mark1 (mark2 (mark2 (mark1 id)))) id)
(bound-identifier=? (mark1 (mark2 (mark1 (mark2 id)))) id)

In the curent version of Rackert, both results are #t.

IIRC up to version 6.2 the results were #t and #f, because marks could only remove a "consecutive" identical mark.

1 Like

I see. I think syntax-marks are commutative now, as the Racket Reference make it pretty clear that the scopes associated with a syntax object form a scope set.