Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Michael Ballantyne
As Alexis notes, getting the arrows right in general is tricky. But `block` 
is also currently buggy in that it does not expand to `#%expression` when 
not in an expression context. (`block` is buggy in at least one other way 
as well, but that needs a deeper fix: 
https://github.com/racket/racket/issues/3198)

On Sunday, June 7, 2020 at 4:45:34 PM UTC-6, Sorawee Porncharoenwase wrote:
>
> Wow, so block is currently buggy?!
>
> On Sun, Jun 7, 2020 at 3:31 PM Michael Ballantyne  > wrote:
>
>> Hah! You're right. The arrow points to the inner definition. But it's 
>> even worse than that---the value comes from the outer definition! At least 
>> for `block`, which is what I'm testing with as I haven't copied down your 
>> code. Try this:
>>
>> #lang racket
>>
>> (require racket/block)
>>
>> (define-syntax-rule (m) (displayln 'old))
>>
>> (let ()
>>   (block (m))
>>   (define-syntax-rule (m) 'new)
>>   (void))
>>
>> (and with your macro rather than block)
>>
>> On Sunday, June 7, 2020 at 4:27:24 PM UTC-6, Sorawee Porncharoenwase 
>> wrote:
>>>
>>> Perhaps I missed something, but the error in the first example is 
>>> because there’s no expression at the end of let. If I use this code 
>>> instead, it seems to work fine, with the arrow of m pointing to the 
>>> “new” one.
>>>
>>> (define-syntax-rule (m) 'old)
>>>
>>> (let ()
>>>   (list+ (m))
>>>   (define-syntax-rule (m) 'new)
>>>   (void))
>>>
>>> The second example perfectly shows why I need 
>>> internal-definition-context-track, however. Thank you very much.
>>>
>>> On Sun, Jun 7, 2020 at 7:51 AM Michael Ballantyne  
>>> wrote:
>>>
 >  I am unable to come up with a program where this difference is 
 significant though

 Here's an example:

 (define-syntax-rule (m) 'old)

 (let ()
   ($list
(m))
   (define-syntax-rule (m) 'new))


 > So I am curious why internal-definition-context-track is needed.

 A similar example shows the need here:

 ($list
   (define-syntax-rule (m) 5)
   (m))

 Without `internal-definition-context-track` you'll miss the arrow for 
 `m`. While `m` does indeed get rebound in the `letrec-syntaxes+values`, 
 that binding has an extra scope, so the reference to `m` (recorded in an 
 `'origin` property on `5`) doesn't match. 



 On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase 
 wrote:
>
> Thank you so much, Michael! This is very helpful.
>
> I can see that when this form is used within another internal 
> definition context, then my version and your version will expand in 
> different order, and I agree that yours makes more sense. I am unable to 
> come up with a program where this difference is significant though (e.g., 
> one fails while the other doesn’t). “so that names bound by later 
> definitions are available” seems to suggest that things like this is not 
> supposed to work on my version:
>
> (let ()
>   ($list (define (f x) (g x))
>  (println f))
>   (define (g x) x)
>   (void))
>
> but it actually does…
>
> I also have another question. When should I use 
> internal-definition-context-track? Normally, internal definitions are 
> expanded into letrec-syntaxes+values, so the bindings don’t actually 
> disappear. So I am curious why internal-definition-context-track is 
> needed.
>
> Thanks again.
>
> On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne <
> michael@gmail.com> wrote:
>
>> Explicitly expanding `e` would ensure that the expansion work only 
>> has to happen once, rather than twice. Even so, the fully-expanded 
>> syntax 
>> will be expanded again in `syntax-local-bind-syntaxes` and in the 
>> expansion.
>>
>> As far as I've seen, the only thing that liberal define contexts 
>> control is whether definitions of functions that accept keyword 
>> arguments 
>> expand to a normal `define-values` with runtime handling of keywords, or 
>> expand to a collection of macros and function definitions that allow a 
>> more 
>> efficient calling convention for first-order calls. The latter expansion 
>> doesn't work for contexts like `class` where function definitions are 
>> re-interpreted in a way that adds indirection, so it is only enabled in 
>> contexts that opt-in.
>>
>> I see more bug in your macro: as its very first task, it should check 
>> if `(syntax-local-context)` is `'expression`. If not, it should expand 
>> to 
>> `(#%expression )`. This ensures that its expansion is 
>> delayed until the second pass of the surrounding definition context so 
>> that 
>> names bound by later definitions are available. 
>>
>> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee 
>> Porncharoenwase wrote:
>>>
>>> Ah, apparently I need 

Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Sorawee Porncharoenwase
Wow, so block is currently buggy?!

On Sun, Jun 7, 2020 at 3:31 PM Michael Ballantyne <
michael.ballant...@gmail.com> wrote:

> Hah! You're right. The arrow points to the inner definition. But it's even
> worse than that---the value comes from the outer definition! At least for
> `block`, which is what I'm testing with as I haven't copied down your code.
> Try this:
>
> #lang racket
>
> (require racket/block)
>
> (define-syntax-rule (m) (displayln 'old))
>
> (let ()
>   (block (m))
>   (define-syntax-rule (m) 'new)
>   (void))
>
> (and with your macro rather than block)
>
> On Sunday, June 7, 2020 at 4:27:24 PM UTC-6, Sorawee Porncharoenwase wrote:
>>
>> Perhaps I missed something, but the error in the first example is because
>> there’s no expression at the end of let. If I use this code instead, it
>> seems to work fine, with the arrow of m pointing to the “new” one.
>>
>> (define-syntax-rule (m) 'old)
>>
>> (let ()
>>   (list+ (m))
>>   (define-syntax-rule (m) 'new)
>>   (void))
>>
>> The second example perfectly shows why I need
>> internal-definition-context-track, however. Thank you very much.
>>
>> On Sun, Jun 7, 2020 at 7:51 AM Michael Ballantyne 
>> wrote:
>>
>>> >  I am unable to come up with a program where this difference is
>>> significant though
>>>
>>> Here's an example:
>>>
>>> (define-syntax-rule (m) 'old)
>>>
>>> (let ()
>>>   ($list
>>>(m))
>>>   (define-syntax-rule (m) 'new))
>>>
>>>
>>> > So I am curious why internal-definition-context-track is needed.
>>>
>>> A similar example shows the need here:
>>>
>>> ($list
>>>   (define-syntax-rule (m) 5)
>>>   (m))
>>>
>>> Without `internal-definition-context-track` you'll miss the arrow for
>>> `m`. While `m` does indeed get rebound in the `letrec-syntaxes+values`,
>>> that binding has an extra scope, so the reference to `m` (recorded in an
>>> `'origin` property on `5`) doesn't match.
>>>
>>>
>>>
>>> On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase
>>> wrote:

 Thank you so much, Michael! This is very helpful.

 I can see that when this form is used within another internal
 definition context, then my version and your version will expand in
 different order, and I agree that yours makes more sense. I am unable to
 come up with a program where this difference is significant though (e.g.,
 one fails while the other doesn’t). “so that names bound by later
 definitions are available” seems to suggest that things like this is not
 supposed to work on my version:

 (let ()
   ($list (define (f x) (g x))
  (println f))
   (define (g x) x)
   (void))

 but it actually does…

 I also have another question. When should I use
 internal-definition-context-track? Normally, internal definitions are
 expanded into letrec-syntaxes+values, so the bindings don’t actually
 disappear. So I am curious why internal-definition-context-track is
 needed.

 Thanks again.

 On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne <
 michael@gmail.com> wrote:

> Explicitly expanding `e` would ensure that the expansion work only has
> to happen once, rather than twice. Even so, the fully-expanded syntax will
> be expanded again in `syntax-local-bind-syntaxes` and in the expansion.
>
> As far as I've seen, the only thing that liberal define contexts
> control is whether definitions of functions that accept keyword arguments
> expand to a normal `define-values` with runtime handling of keywords, or
> expand to a collection of macros and function definitions that allow a 
> more
> efficient calling convention for first-order calls. The latter expansion
> doesn't work for contexts like `class` where function definitions are
> re-interpreted in a way that adds indirection, so it is only enabled in
> contexts that opt-in.
>
> I see more bug in your macro: as its very first task, it should check
> if `(syntax-local-context)` is `'expression`. If not, it should expand to
> `(#%expression )`. This ensures that its expansion is
> delayed until the second pass of the surrounding definition context so 
> that
> names bound by later definitions are available.
>
> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase
> wrote:
>>
>> Ah, apparently I need syntax-local-identifier-as-binding. Here’s a
>> revised code that passes the tests.
>>
>> (begin-for-syntax
>>   (define ((do-it gs ctx) e)
>> (let loop ([e e])
>>   (define e-expanded (local-expand e
>>(list gs)
>>(list #'begin
>>  #'define-syntaxes
>>  #'define-values)
>>ctx))
>>   (syntax-parse e-expanded

Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Michael Ballantyne
Hah! You're right. The arrow points to the inner definition. But it's even 
worse than that---the value comes from the outer definition! At least for 
`block`, which is what I'm testing with as I haven't copied down your code. 
Try this:

#lang racket

(require racket/block)

(define-syntax-rule (m) (displayln 'old))

(let ()
  (block (m))
  (define-syntax-rule (m) 'new)
  (void))

(and with your macro rather than block)

On Sunday, June 7, 2020 at 4:27:24 PM UTC-6, Sorawee Porncharoenwase wrote:
>
> Perhaps I missed something, but the error in the first example is because 
> there’s no expression at the end of let. If I use this code instead, it 
> seems to work fine, with the arrow of m pointing to the “new” one.
>
> (define-syntax-rule (m) 'old)
>
> (let ()
>   (list+ (m))
>   (define-syntax-rule (m) 'new)
>   (void))
>
> The second example perfectly shows why I need 
> internal-definition-context-track, however. Thank you very much.
>
> On Sun, Jun 7, 2020 at 7:51 AM Michael Ballantyne  > wrote:
>
>> >  I am unable to come up with a program where this difference is 
>> significant though
>>
>> Here's an example:
>>
>> (define-syntax-rule (m) 'old)
>>
>> (let ()
>>   ($list
>>(m))
>>   (define-syntax-rule (m) 'new))
>>
>>
>> > So I am curious why internal-definition-context-track is needed.
>>
>> A similar example shows the need here:
>>
>> ($list
>>   (define-syntax-rule (m) 5)
>>   (m))
>>
>> Without `internal-definition-context-track` you'll miss the arrow for 
>> `m`. While `m` does indeed get rebound in the `letrec-syntaxes+values`, 
>> that binding has an extra scope, so the reference to `m` (recorded in an 
>> `'origin` property on `5`) doesn't match. 
>>
>>
>>
>> On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase 
>> wrote:
>>>
>>> Thank you so much, Michael! This is very helpful.
>>>
>>> I can see that when this form is used within another internal definition 
>>> context, then my version and your version will expand in different order, 
>>> and I agree that yours makes more sense. I am unable to come up with a 
>>> program where this difference is significant though (e.g., one fails while 
>>> the other doesn’t). “so that names bound by later definitions are 
>>> available” seems to suggest that things like this is not supposed to work 
>>> on my version:
>>>
>>> (let ()
>>>   ($list (define (f x) (g x))
>>>  (println f))
>>>   (define (g x) x)
>>>   (void))
>>>
>>> but it actually does…
>>>
>>> I also have another question. When should I use 
>>> internal-definition-context-track? Normally, internal definitions are 
>>> expanded into letrec-syntaxes+values, so the bindings don’t actually 
>>> disappear. So I am curious why internal-definition-context-track is 
>>> needed.
>>>
>>> Thanks again.
>>>
>>> On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne  
>>> wrote:
>>>
 Explicitly expanding `e` would ensure that the expansion work only has 
 to happen once, rather than twice. Even so, the fully-expanded syntax will 
 be expanded again in `syntax-local-bind-syntaxes` and in the expansion.

 As far as I've seen, the only thing that liberal define contexts 
 control is whether definitions of functions that accept keyword arguments 
 expand to a normal `define-values` with runtime handling of keywords, or 
 expand to a collection of macros and function definitions that allow a 
 more 
 efficient calling convention for first-order calls. The latter expansion 
 doesn't work for contexts like `class` where function definitions are 
 re-interpreted in a way that adds indirection, so it is only enabled in 
 contexts that opt-in.

 I see more bug in your macro: as its very first task, it should check 
 if `(syntax-local-context)` is `'expression`. If not, it should expand to 
 `(#%expression )`. This ensures that its expansion is 
 delayed until the second pass of the surrounding definition context so 
 that 
 names bound by later definitions are available. 

 On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase 
 wrote:
>
> Ah, apparently I need syntax-local-identifier-as-binding. Here’s a 
> revised code that passes the tests.
>
> (begin-for-syntax
>   (define ((do-it gs ctx) e)
> (let loop ([e e])
>   (define e-expanded (local-expand e
>(list gs)
>(list #'begin
>  #'define-syntaxes
>  #'define-values)
>ctx))
>   (syntax-parse e-expanded
> #:literals (begin define-syntaxes define-values)
> [(begin body ...) #`(begin #,@(map loop (attribute body)))]
> [(define-values (x ...) e)
>  #:with (x* ...) (map syntax-local-identifier-as-binding
>  

Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Sorawee Porncharoenwase
Perhaps I missed something, but the error in the first example is because
there’s no expression at the end of let. If I use this code instead, it
seems to work fine, with the arrow of m pointing to the “new” one.

(define-syntax-rule (m) 'old)

(let ()
  (list+ (m))
  (define-syntax-rule (m) 'new)
  (void))

The second example perfectly shows why I need
internal-definition-context-track, however. Thank you very much.

On Sun, Jun 7, 2020 at 7:51 AM Michael Ballantyne <
michael.ballant...@gmail.com> wrote:

> >  I am unable to come up with a program where this difference is
> significant though
>
> Here's an example:
>
> (define-syntax-rule (m) 'old)
>
> (let ()
>   ($list
>(m))
>   (define-syntax-rule (m) 'new))
>
>
> > So I am curious why internal-definition-context-track is needed.
>
> A similar example shows the need here:
>
> ($list
>   (define-syntax-rule (m) 5)
>   (m))
>
> Without `internal-definition-context-track` you'll miss the arrow for `m`.
> While `m` does indeed get rebound in the `letrec-syntaxes+values`, that
> binding has an extra scope, so the reference to `m` (recorded in an
> `'origin` property on `5`) doesn't match.
>
>
>
> On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase
> wrote:
>>
>> Thank you so much, Michael! This is very helpful.
>>
>> I can see that when this form is used within another internal definition
>> context, then my version and your version will expand in different order,
>> and I agree that yours makes more sense. I am unable to come up with a
>> program where this difference is significant though (e.g., one fails while
>> the other doesn’t). “so that names bound by later definitions are
>> available” seems to suggest that things like this is not supposed to work
>> on my version:
>>
>> (let ()
>>   ($list (define (f x) (g x))
>>  (println f))
>>   (define (g x) x)
>>   (void))
>>
>> but it actually does…
>>
>> I also have another question. When should I use
>> internal-definition-context-track? Normally, internal definitions are
>> expanded into letrec-syntaxes+values, so the bindings don’t actually
>> disappear. So I am curious why internal-definition-context-track is
>> needed.
>>
>> Thanks again.
>>
>> On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne 
>> wrote:
>>
>>> Explicitly expanding `e` would ensure that the expansion work only has
>>> to happen once, rather than twice. Even so, the fully-expanded syntax will
>>> be expanded again in `syntax-local-bind-syntaxes` and in the expansion.
>>>
>>> As far as I've seen, the only thing that liberal define contexts control
>>> is whether definitions of functions that accept keyword arguments expand to
>>> a normal `define-values` with runtime handling of keywords, or expand to a
>>> collection of macros and function definitions that allow a more efficient
>>> calling convention for first-order calls. The latter expansion doesn't work
>>> for contexts like `class` where function definitions are re-interpreted in
>>> a way that adds indirection, so it is only enabled in contexts that opt-in.
>>>
>>> I see more bug in your macro: as its very first task, it should check if
>>> `(syntax-local-context)` is `'expression`. If not, it should expand to
>>> `(#%expression )`. This ensures that its expansion is
>>> delayed until the second pass of the surrounding definition context so that
>>> names bound by later definitions are available.
>>>
>>> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase
>>> wrote:

 Ah, apparently I need syntax-local-identifier-as-binding. Here’s a
 revised code that passes the tests.

 (begin-for-syntax
   (define ((do-it gs ctx) e)
 (let loop ([e e])
   (define e-expanded (local-expand e
(list gs)
(list #'begin
  #'define-syntaxes
  #'define-values)
ctx))
   (syntax-parse e-expanded
 #:literals (begin define-syntaxes define-values)
 [(begin body ...) #`(begin #,@(map loop (attribute body)))]
 [(define-values (x ...) e)
  #:with (x* ...) (map syntax-local-identifier-as-binding
   (attribute x))
  (syntax-local-bind-syntaxes (attribute x) #f ctx)
  #'(define-values (x* ...) e)]
 [(define-syntaxes (x ...) e)
  #:with (x* ...) (map syntax-local-identifier-as-binding
   (attribute x))
  (syntax-local-bind-syntaxes (attribute x) #'e ctx)
  #'(define-syntaxes (x* ...) e)]
 [e #'(set! acc (cons e acc))]

 Still not sure if there’s still anything wrong. In particular, do I
 need to expand e in define-syntaxes? And do I need to use
 prop:liberal-define-context for gs? (I 

Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Michael Ballantyne
>  I am unable to come up with a program where this difference is 
significant though

Here's an example:

(define-syntax-rule (m) 'old)

(let ()
  ($list
   (m))
  (define-syntax-rule (m) 'new))


> So I am curious why internal-definition-context-track is needed.

A similar example shows the need here:

($list
  (define-syntax-rule (m) 5)
  (m))

Without `internal-definition-context-track` you'll miss the arrow for `m`. 
While `m` does indeed get rebound in the `letrec-syntaxes+values`, that 
binding has an extra scope, so the reference to `m` (recorded in an 
`'origin` property on `5`) doesn't match. 



On Sunday, June 7, 2020 at 12:18:26 AM UTC-6, Sorawee Porncharoenwase wrote:
>
> Thank you so much, Michael! This is very helpful.
>
> I can see that when this form is used within another internal definition 
> context, then my version and your version will expand in different order, 
> and I agree that yours makes more sense. I am unable to come up with a 
> program where this difference is significant though (e.g., one fails while 
> the other doesn’t). “so that names bound by later definitions are 
> available” seems to suggest that things like this is not supposed to work 
> on my version:
>
> (let ()
>   ($list (define (f x) (g x))
>  (println f))
>   (define (g x) x)
>   (void))
>
> but it actually does…
>
> I also have another question. When should I use 
> internal-definition-context-track? Normally, internal definitions are 
> expanded into letrec-syntaxes+values, so the bindings don’t actually 
> disappear. So I am curious why internal-definition-context-track is 
> needed.
>
> Thanks again.
>
> On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne  > wrote:
>
>> Explicitly expanding `e` would ensure that the expansion work only has to 
>> happen once, rather than twice. Even so, the fully-expanded syntax will be 
>> expanded again in `syntax-local-bind-syntaxes` and in the expansion.
>>
>> As far as I've seen, the only thing that liberal define contexts control 
>> is whether definitions of functions that accept keyword arguments expand to 
>> a normal `define-values` with runtime handling of keywords, or expand to a 
>> collection of macros and function definitions that allow a more efficient 
>> calling convention for first-order calls. The latter expansion doesn't work 
>> for contexts like `class` where function definitions are re-interpreted in 
>> a way that adds indirection, so it is only enabled in contexts that opt-in.
>>
>> I see more bug in your macro: as its very first task, it should check if 
>> `(syntax-local-context)` is `'expression`. If not, it should expand to 
>> `(#%expression )`. This ensures that its expansion is 
>> delayed until the second pass of the surrounding definition context so that 
>> names bound by later definitions are available. 
>>
>> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase 
>> wrote:
>>>
>>> Ah, apparently I need syntax-local-identifier-as-binding. Here’s a 
>>> revised code that passes the tests.
>>>
>>> (begin-for-syntax
>>>   (define ((do-it gs ctx) e)
>>> (let loop ([e e])
>>>   (define e-expanded (local-expand e
>>>(list gs)
>>>(list #'begin
>>>  #'define-syntaxes
>>>  #'define-values)
>>>ctx))
>>>   (syntax-parse e-expanded
>>> #:literals (begin define-syntaxes define-values)
>>> [(begin body ...) #`(begin #,@(map loop (attribute body)))]
>>> [(define-values (x ...) e)
>>>  #:with (x* ...) (map syntax-local-identifier-as-binding
>>>   (attribute x))
>>>  (syntax-local-bind-syntaxes (attribute x) #f ctx)
>>>  #'(define-values (x* ...) e)]
>>> [(define-syntaxes (x ...) e)
>>>  #:with (x* ...) (map syntax-local-identifier-as-binding
>>>   (attribute x))
>>>  (syntax-local-bind-syntaxes (attribute x) #'e ctx)
>>>  #'(define-syntaxes (x* ...) e)]
>>> [e #'(set! acc (cons e acc))]
>>>
>>> Still not sure if there’s still anything wrong. In particular, do I need 
>>> to expand e in define-syntaxes? And do I need to use 
>>> prop:liberal-define-context for gs? (I don’t understand what liberal 
>>> expansion is even after reading the docs several times) Both of these are 
>>> done in the implementation of block, but without them, it seems to work 
>>> equally well.
>>>
>>> On Fri, Jun 5, 2020 at 6:30 PM Sorawee Porncharoenwase <
>>> sorawe...@gmail.com> wrote:
>>>
 Hi Racketeers,

 I’m creating a macro that collects values in the internal-definition 
 context. E.g.,

 ($list 
  1
  (define x 2)
  x)

 should evaluate to '(1 2).

 Here’s my implementation, and it kinda works:

 #lang racket

 

Re: [racket-users] Re: identifier used out of context

2020-06-07 Thread Sorawee Porncharoenwase
Thank you so much, Michael! This is very helpful.

I can see that when this form is used within another internal definition
context, then my version and your version will expand in different order,
and I agree that yours makes more sense. I am unable to come up with a
program where this difference is significant though (e.g., one fails while
the other doesn’t). “so that names bound by later definitions are
available” seems to suggest that things like this is not supposed to work
on my version:

(let ()
  ($list (define (f x) (g x))
 (println f))
  (define (g x) x)
  (void))

but it actually does…

I also have another question. When should I use
internal-definition-context-track? Normally, internal definitions are
expanded into letrec-syntaxes+values, so the bindings don’t actually
disappear. So I am curious why internal-definition-context-track is needed.

Thanks again.

On Sat, Jun 6, 2020 at 8:21 AM Michael Ballantyne <
michael.ballant...@gmail.com> wrote:

> Explicitly expanding `e` would ensure that the expansion work only has to
> happen once, rather than twice. Even so, the fully-expanded syntax will be
> expanded again in `syntax-local-bind-syntaxes` and in the expansion.
>
> As far as I've seen, the only thing that liberal define contexts control
> is whether definitions of functions that accept keyword arguments expand to
> a normal `define-values` with runtime handling of keywords, or expand to a
> collection of macros and function definitions that allow a more efficient
> calling convention for first-order calls. The latter expansion doesn't work
> for contexts like `class` where function definitions are re-interpreted in
> a way that adds indirection, so it is only enabled in contexts that opt-in.
>
> I see more bug in your macro: as its very first task, it should check if
> `(syntax-local-context)` is `'expression`. If not, it should expand to
> `(#%expression )`. This ensures that its expansion is
> delayed until the second pass of the surrounding definition context so that
> names bound by later definitions are available.
>
> On Saturday, June 6, 2020 at 4:15:00 AM UTC-6, Sorawee Porncharoenwase
> wrote:
>>
>> Ah, apparently I need syntax-local-identifier-as-binding. Here’s a
>> revised code that passes the tests.
>>
>> (begin-for-syntax
>>   (define ((do-it gs ctx) e)
>> (let loop ([e e])
>>   (define e-expanded (local-expand e
>>(list gs)
>>(list #'begin
>>  #'define-syntaxes
>>  #'define-values)
>>ctx))
>>   (syntax-parse e-expanded
>> #:literals (begin define-syntaxes define-values)
>> [(begin body ...) #`(begin #,@(map loop (attribute body)))]
>> [(define-values (x ...) e)
>>  #:with (x* ...) (map syntax-local-identifier-as-binding
>>   (attribute x))
>>  (syntax-local-bind-syntaxes (attribute x) #f ctx)
>>  #'(define-values (x* ...) e)]
>> [(define-syntaxes (x ...) e)
>>  #:with (x* ...) (map syntax-local-identifier-as-binding
>>   (attribute x))
>>  (syntax-local-bind-syntaxes (attribute x) #'e ctx)
>>  #'(define-syntaxes (x* ...) e)]
>> [e #'(set! acc (cons e acc))]
>>
>> Still not sure if there’s still anything wrong. In particular, do I need
>> to expand e in define-syntaxes? And do I need to use
>> prop:liberal-define-context for gs? (I don’t understand what liberal
>> expansion is even after reading the docs several times) Both of these are
>> done in the implementation of block, but without them, it seems to work
>> equally well.
>>
>> On Fri, Jun 5, 2020 at 6:30 PM Sorawee Porncharoenwase <
>> sorawe...@gmail.com> wrote:
>>
>>> Hi Racketeers,
>>>
>>> I’m creating a macro that collects values in the internal-definition
>>> context. E.g.,
>>>
>>> ($list
>>>  1
>>>  (define x 2)
>>>  x)
>>>
>>> should evaluate to '(1 2).
>>>
>>> Here’s my implementation, and it kinda works:
>>>
>>> #lang racket
>>>
>>> (begin-for-syntax
>>>   (define ((do-it gs ctx) e)
>>> (let loop ([e e])
>>>   (define e-expanded (local-expand e (list gs) #f ctx))
>>>   (syntax-case e-expanded (begin define-syntaxes define-values)
>>> [(begin body ...)
>>>  #`(begin #,@(map loop (syntax->list #'(body ...]
>>> [(define-values ids e)
>>>  (begin
>>>(syntax-local-bind-syntaxes (syntax->list #'ids) #f ctx)
>>>e-expanded)]
>>> [(define-syntaxes ids e)
>>>  (begin
>>>(syntax-local-bind-syntaxes (syntax->list #'ids) #'e ctx)
>>>#'(begin))]
>>> [e #'(set! acc (cons e acc))]
>>>
>>> (define-syntax ($list stx)
>>>   (define gs (gensym))
>>>   (define ctx (syntax-local-make-definition-context))
>>>   (syntax-case stx ()
>>> [(_