Wow, I really butchered a sentence. Let me try it again. Old: "That is, there's a compile-time "pass" where Racket is focuses on the code you write and what they can see"
New: "That is, there's a compile-time "pass" where Racket focuses on replacing used macros with new code, and that pass has its own set of bindings that only that pass can see." ~slg -------- Original Message -------- On May 9, 2021, 3:14 PM, Sage Gerard wrote: > I'm stretching details a bit, but maybe it would help to think of phases as > "passes." That is, there's a compile-time "pass" where Racket is focuses on > the code you write and what they can see. These passes continue until the > Racket program is fully expanded. > > Where things get tricky is remembering that when you create a binding at one > phase, it is available for that phase. It's a little easier to tell the > difference across module boundaries. > > Let's say you have a library that defines your functions at phase 0, or > runtime. > > ; lib.rkt > #lang racket/base > (provide (all-defined-out)) > (define (my-function x) (+ x 1)) (define (my-macro stx) > (datum->syntax stx (my-function (cadr (syntax->datum stx))))) > > Now let's have another module use the syntax transformer. I'm handwaving > around some details because `define-syntax` and `define-for-syntax` are not > the same, but I'd like to focus on illustrating how phases operate. > > #lang racket/base > (require "lib.rkt") > (my-macro #'(x 1)) > > The reason this works is because all the bindings are in the same phase. That > is, everything was defined in the same pass. Now let's shift it all one phase > up, which will break the program because it no longer sees my-macro, or even > enough of racket/base to apply functions. > > #lang racket/base > (require (for-syntax "lib.rkt")) > (my-macro #'(x 1)) > > Right now `my-macro` is in phase 1 relative to this module. So we have to > "lift" the rest of the code to match. > > #lang racket/base > (require (for-syntax racket/base "lib.rkt")) > (begin-for-syntax (my-macro #'(x 1))) > > This still isn't particularly useful because most of the time, a module > manages multiple phases at once. It can be harder to visualize, but the > principle is the same: When code runs at a certain phase, is everything that > code needs to run also available at that phase? It's still just Racket. I > like to visualize it as running at a different "layer" on top of the code > that I know will eventually execute at runtime. Here's another example that > can help drive the point home. Run it using the `racket` command. > > #lang racket/base > (require (for-syntax racket/base)) > > (define a "foo") > (define-for-syntax a 1) > > (displayln a) > (begin-for-syntax (displayln a)) > > Notice that you see "1" first, before "foo", even though the displayln for > the "1" is after the displayln for "foo". > > So to answer your question, if you have something you want available across > phases, you need to bind that same value across phases. Here's a simplified > example. > > #lang racket/base > (require (for-syntax racket/base)) > > (define-syntax-rule (define-across-phases id v) > (begin (define id v) > (define-for-syntax id v))) > > (define-across-phases a 1) > > (displayln a) > > (begin-for-syntax (displayln a)) > > Notice that I leverage a phase to define an identifier twice: Once for the > current phase, and once for the phase +1 "layer" up. > > But... I normally do bind across phases using (require) with both for-syntax > and without a phase shift. e.g. (require "lib.rkt" (for-syntax "lib.rkt")). > There are times I'll need cross-phase definitions only within one module, but > it doesn't come up much for me. > > Hope this helps. > > On 5/9/21 3:53 AM, Yushuo Xiao wrote: > >> I am using syntax transformers to define macros in Racket. I want to create >> some helper functions to help me manipulate the syntax. However, the >> functions I defined outside the syntax transformer are not available inside >> the syntax transformer. For example, in the following code >> >> (define (my-function x) (+ x 1)) >> >> (define-syntax my-macro >> (lambda (stx) >> (datum->syntax stx (my-function (cadr (syntax->datum stx)))))) >> >> I got the error "my-function: reference to an unbound identifier at phase: >> 1; the transformer environment". >> >> After some searching, I am able to write the following code so that >> `my-function` is available inside the syntax transformer. >> >> (begin-for-syntax >> (define (my-function x) (+ x 1))) >> (provide (for-syntax my-function)) >> >> (define-syntax my-macro >> (lambda (stx) >> (datum->syntax stx (my-function (cadr (syntax->datum stx)))))) >> >> But the problem is, `my-function` is not available outside the syntax >> transformer this time. Sometimes I want to check those helper functions in >> ordinary code, so I need to be able to call it from both inside and outside >> the syntax transformer, just like the function `cadr`. How can I achieve >> that? >> >> I know my question has something to do with Racket's syntax model, in >> particular the concept of "phase level", but I never really understand it. >> If you could provide some easy-to-follow tutorials explaining it I would >> even be more grateful. >> -- >> 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/46cce5b2-251b-481c-afe2-28582e8c44f3n%40googlegroups.com](https://groups.google.com/d/msgid/racket-users/46cce5b2-251b-481c-afe2-28582e8c44f3n%40googlegroups.com?utm_medium=email&utm_source=footer). > > -- > ~slg > > -- > 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/02b5016d-67f8-f44d-2924-c7f1b4c022a0%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/02b5016d-67f8-f44d-2924-c7f1b4c022a0%40sagegerard.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/v3kmdKboUfKmBf9GVBIiEjBTy2eXWqaJziKOXcLlnZbvJTt4K2W1P-I6SskzJ26H4Sr0FZCdxB9FWaJWsEJUih0TcYvgpTlrI8Hn572kh1k%3D%40sagegerard.com.

