syntax-local-lift-expression vs. syntax-local-lift-require

78 views
Skip to first unread message

Matthew Butterick

unread,
Feb 27, 2017, 4:40:50 PM2/27/17
to Racket Users
Is there a simple way to lift a `require` form to the top level of a module? i.e., in the example below, is there something that would replace `WHAT-MAGIC-GOES-HERE?` to make it work?

I understand that `syntax-local-lift-expression` won't work.

But `syntax-local-lift-require`, as best I can divine, needs you to furnish a particular identifier as the second argument, and incurs other housekeeping with scopes. So, though I'm not really sure what it's for, I'm pretty sure it's not for this.

(FWIW `syntax-local-lift-module-end-declaration` didn't work either.)


;;;;;;;;;;;;;;;;;;;;

#lang racket

(define-syntax (lifted-require stx)
(syntax-case stx ()
[(_ spec) (WHAT-MAGIC-GOES-HERE? #'(require spec))]))

(let ()
(lifted-require math/number-theory))

Message has been deleted

gfb

unread,
Feb 27, 2017, 8:34:53 PM2/27/17
to Racket Users
On Monday, 27 February 2017 16:40:50 UTC-5, Matthew Butterick wrote:
> Is there a simple way to lift a `require` form to the top level of a module? i.e., in the example below, is there something that would replace `WHAT-MAGIC-GOES-HERE?` to make it work?
>
> I understand that `syntax-local-lift-expression` won't work.
>
> But `syntax-local-lift-require`, as best I can divine, needs you to furnish a particular identifier as the second argument, and incurs other housekeeping with scopes. So, though I'm not really sure what it's for, I'm pretty sure it's not for this.

It appears to be for `local-require` behaviour: being able to use the required identifiers locally in the syntax object you give it.

>
> (FWIW `syntax-local-lift-module-end-declaration` didn't work either.)
>
>
> ;;;;;;;;;;;;;;;;;;;;
>
> #lang racket
>
> (define-syntax (lifted-require stx)
> (syntax-case stx ()
> [(_ spec) (WHAT-MAGIC-GOES-HERE? #'(require spec))]))
>
> (let ()
> (lifted-require math/number-theory))

If you want that to be equivalent to having `(require math/number-theory)` at the top-level then I'm not sure the precise semantics: should it affect the meaning of already-transformed code from before that `lifted-require` was encountered? Recall that `requires` are noted before expansion of other forms, so, e.g., this works:

#lang racket
divides? ; Even though the require for this appears after
(require math/number-theory)

Matthew Butterick

unread,
Feb 27, 2017, 9:43:34 PM2/27/17
to Racket Users
> On Feb 27, 2017, at 4:51 PM, Jay McCarthy <jay.mc...@gmail.com> wrote:
>
> You don't want local-require?



I don't think so — the `require` forms can be nested anywhere in the program. I want them to jump to the top level, and have their usual "global" effect.


> On Feb 27, 2017, at 5:34 PM, gfb <g...@cs.toronto.edu> wrote:
>
> If you want that to be equivalent to having `(require math/number-theory)` at the top-level then I'm not sure the precise semantics: should it affect the meaning of already-transformed code from before that `lifted-require` was encountered?

Currently, I'm doing the job by hand: that is, in the expansion of the `#%module-begin` of my #lang, I search the inbound parse tree and move the `require` forms to the top level. This works fine.

So I suppose my question boils down to "is there something in the syntax-function zoo that does this more neatly?"

As it stands, I think the answer is "no" because my manual technique is essentially pre-empting the macro expander.

Matthew Flatt

unread,
Feb 27, 2017, 10:04:07 PM2/27/17
to Matthew Butterick, Racket Users
At Mon, 27 Feb 2017 18:43:28 -0800, Matthew Butterick wrote:
> > On Feb 27, 2017, at 5:34 PM, gfb <g...@cs.toronto.edu> wrote:
> >
> > If you want that to be equivalent to having `(require
> > math/number-theory)` at the top-level then I'm not sure the precise
> > semantics: should it affect the meaning of already-transformed code
> > from before that `lifted-require` was encountered?
>
> Currently, I'm doing the job by hand: that is, in the expansion of the
> `#%module-begin` of my #lang, I search the inbound parse tree and move the
> `require` forms to the top level. This works fine.
>
> So I suppose my question boils down to "is there something in the
> syntax-function zoo that does this more neatly?"
>
> As it stands, I think the answer is "no" because my manual technique is
> essentially pre-empting the macro expander.

Right.

The `syntax-local-lift-require` function works the way it does to avoid
the potential ambiguity Gary suggests, where adding a `require` from a
nested expression could create a binding that would affect expansion of
surrounding forms (but it's too late for that).

By adding the `require` in a fresh scope and then indirectly giving you
the scope, the effect of the `require` is consistently limited to
expressions that are afterwards given the new scope.


At Mon, 27 Feb 2017 17:34:53 -0800 (PST), gfb wrote:
> Recall that `requires` are noted before expansion of other forms,
> so, e.g., this works:
>
> #lang racket
> divides? ; Even though the require for this appears after
> (require math/number-theory)

Well, ok... there is some ambiguity here. It's not that `require`s are
noted before other expansion, but that module-level expansions are
partial until all the `defines` and `requires` are found. So `divides?`
is determined not to be a definition by partial expansion, and further
expansion is delayed under the assumption that `divides?` is an
expression form. If `divides?` turns out to be a definition form, it
will trigger an error. In contrast, if `divides?` is put after
`(require math/number-theory)`, then it's ok for `divides?` to expand
as a definition.

This partial-expansion idea has worked ok, and so we've put up with
this much order-sensitive behavior, but we try to minimize it.

Reply all
Reply to author
Forward
0 new messages