8000
Skip to content

Add syntax-local-binding, a generalized version of syntax-local-value#2300

Open
lexi-lambda wants to merge 1 commit intoracket:masterfrom
lexi-lambda:syntax-local-binding
Open

Add syntax-local-binding, a generalized version of syntax-local-value#2300
lexi-lambda wants to merge 1 commit intoracket:masterfrom
lexi-lambda:syntax-local-binding

Conversation

@lexi-lambda
Copy link
Copy Markdown
Member

First-class definition contexts provide general-purpose control of the local binding context, but syntax-local-value only provides a limited way to inspect it: it cannot distinguish between out-of-context bindings and in-context variables. This commit adds a new function, syntax-local-binding, which provides precisely the missing functionality.

This commit also adds an #:immediate? keyword argument to syntax-local-value to make it more consistent with syntax-local-binding, eliminating the need for a separate syntax-local-value/immediate function (though of course it must be retained for backwards compatibility).

@lexi-lambda lexi-lambda requested a review from mflatt October 5, 2018 19:49
First-class definition contexts provide general-purpose control of the
local binding context, but syntax-local-value only provides a limited
way to inspect it: it cannot distinguish between out-of-context
identifiers and in-context variables. This commit adds
syntax-local-binding, which provides precisely the missing
functionality.

This commit also adds an #:immediate? keyword argument to
syntax-local-value to make it more consistent with syntax-local-binding
and eliminating the need for a separate syntax-local-value/immediate
function.
@lexi-lambda lexi-lambda force-pushed the syntax-local-binding branch from 6bf3d1e to 5ad4988 Compare October 5, 2018 19:50
@michaelballantyne
Copy link
Copy Markdown
Contributor

I certainly approve of extending the API to be able to distinguish these situations! I have an alternate design proposal I'll throw into the ring, though.

I think that these APIs can be designed in two different ways:

  1. A design that assumes the API is being used for expansion of "normal" Racket code and syntax transformers.
  2. A design that doesn't privilege "normal" Racket expansion versus expansion of a totally non-Racket language using the same infrastructure.

local-expand is an example of 1; it has has special behavior for Racket variable references, potentially Racket-specific notions like function application, and has stop-list behavior tuned to Racket's definition context forms. In contrast, local-apply-transformer is an example of 2; it provides access to the same hygiene mechanism used by local-expand, but in a very generic way that doesn't assume we're expanding Racket syntax.

I find that APIs in the second style make things like Turnstile and Hackett easier to write. Ultimately it might be nice to separate the Racket-specific APIs in a totally different part of the expander API and documentation from the generic bits!

Specially segregating bindings for Racket runtime identifiers versus other syntax bindings, as insyntax-local-value and in first return value of syntax-local-binding feels like the Racket-specific style of expander API design.

If we're introducing a new API, I would propose a design that doesn't privilege normal Racket variable bindings as anything special versus other transformer environment entries. We might expose the special internal variable value used in the right hand side of the transformer environment, and have syntax-local-binding return that value. Similarly, use of that value in the second argument of syntax-local-bind-syntaxes would create Racket runtime variable bindings, as using #f in that position does now. (The current behavior would be preserved for backwards compatibility, of course).

@lexi-lambda
Copy link
Copy Markdown
Member Author

If we're introducing a new API, I would propose a design that doesn't privilege normal Racket variable bindings as anything special versus other transformer environment entries. We might expose the special internal variable value used in the right hand side of the transformer environment, and have syntax-local-binding return that value. Similarly, use of that value in the second argument of syntax-local-bind-syntaxes would create Racket runtime variable bindings, as using #f in that position does now. (The current behavior would be preserved for backwards compatibility, of course).

I like this idea. The biggest question to me is what such a value should be named. It obviously can’t just be exported as variable. Singleton values in Racket sometimes start with the-, such as the-unsupplied-arg, so it could follow that naming convention, too, but it still needs a more descriptive name. The obvious name is variable-transformer, but that’s not right, since the whole point is that it isn’t a transformer!

@shhyou shhyou added the component: macro the macro system: expander, syntax parse, other #lang racket macros label Sep 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: macro the macro system: expander, syntax parse, other #lang racket macros

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0