Re: [racket-users] Racket - How to define a function that can be used both in syntax transformers and ordinary code?

2021-05-09 Thread Sage Gerard
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 a

Re: [racket-users] Racket - How to define a function that can be used both in syntax transformers and ordinary code?

2021-05-09 Thread Sage Gerard
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 racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> [https://groups.google.com/d/msgid/racket-users/46cce5b2-251b-481c-afe2-28582e

[racket-users] Racket - How to define a function that can be used both in syntax transformers and ordinary code?

2021-05-09 Thread Yushuo Xiao
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 racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/46cce5b2-251b-481c-afe2-28582e8c44f3n%40googlegroups.com.