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: current racket dynamic web performance in production?

2020-06-07 Thread Neil Van Dyke

Thanks for the info, Brian.

I'm getting the impression that Scheme/Racket Web production serving is 
sorta in same place it has been for the last couple decades: such that a 
really good and prolific developer can make a system work well in 
production, iff they can put in a lot of work beyond off-the-shelf 
components.


When deciding whether to to go Scheme/Racket, we consider the pros -- 
e.g., the linguistic power of Scheme, the ability to attract talent due 
to using a fringe language that people like or want to learn -- and 
weigh them against the greater amount of bespoke work, the necessity to 
then have non-commodity developers who are up to doing that well, and 
the greater risks/unknowns that might not be solved by throwing a larger 
AWS bill at a problem.[1]


For the server project I'll develop this week, it doesn't actually take 
advantage of Scheme, and the project also won't function as a good pilot 
project for scalability, so I'll probably just use Python this 
time.  I'll keep Scheme/Racket in mind for this, as a known-quantity 
backup plan, but probably Scheme/Racket will have to wait until later 
this year for a better opportunity to shine.


There is a GUI frontend project coming up that might be a better 
opportunity for Racket to be useful in production.  It would be 2nd 
generation replacement of a deployed specialized appliance frontend, 
which currently is done in JS in Chrome (no, not the horrifying 
touchscreen Web browser spaceship consoles we heard about the other day 
:), and some special hardware device interfacing.  I've prototyped 
replacing it with with Python Kivy,[2] but I happen to know that 
Racket's GUI library would be easier to use for this purpose, and result 
in more-solid UI operation.


After that, the next opportunity is probably 2nd generation of the 
entire server infrastructure, and we'll have to see what our needs and 
resources are like at that time.  We'll probably have that 2nd-gen work 
in mind if/when we do more engineering hiring later, and, in any case, 
I'd like to be able to hire the kinds of developers who are up to the 
challenges of doing bespoke work that works.[3]



[1] Though I think the risks/unknowns of a less-popular stack aren't 
what many developers are thinking when they flock to the most popular 
tools of the moment because a FAANG does it.  What tools work 
for a FAANG, with massive infrastructure, massive staffing, and the 
practice of routinely shutting down large numbers of projects (and 
making many multi-billion dollar acquisitions of competitors, when the 
FAANG still fails to outperform upstart competitors with their 
project)... aren't necessarily the tools a startup should use, 
with their handful of people who have to wear many hats, and actually 
have individual contributors understand the entire system, in order to 
make it work well enough and to troubleshoot problems rapidly, despite 
very limited resources.


[2] As I was evaluating GUI toolkits, there's ongoing 
bitrotting/abandonware of the desktop GUI space, as development flocked 
to adtech/VC-driven Web sites and smartphone apps, and people started 
favoring embedded massive browser engines (which have pros and cons).  
And it looks to be self-perpetuating, because the non-Web GUI toolkits 
get less attention.  Kivy was one of the few current non-abandoned 
toolkits.  Racket's cross-platform GUI toolkit remains supported for 
solid Win95-era desktop GUIs, and is currently looking better than 
Python and JS-framework-in-WebKit options, for the particular kind of 
(non-consumer) touchscreen appliance console we'll need to do. (For 
slick consumer-facing UIs, I'm currently going through the rapid mood 
swings experience of the SwiftUI DSL and related iOS stack. :)


[3] And I've long believed that using one of the less-popular but 
beloved platforms -- like Scheme/Racket, Common Lisp, Haskell, OCaml, 
Erlang, or Rust -- is a great way to find and attract some of the best 
developers.  FAANGs can say to some of those developers, "we'll pay you 
more money, and everyone else who aspires to make FAANG money will be 
impressed when they see us on your resume", but the toolset you get to 
use can be one of the significant selling points of a competing value 
proposition.


--
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/0d79e2bc-536c-a6da-5c15-3d84790864cc%40neilvandyke.org.


Re: [racket-users] Is it possible to simulate FEXPRs in Racket?

2020-06-07 Thread Jens Axel Søgaard
Den søn. 7. jun. 2020 kl. 14.09 skrev Siyuan Chen :

Unfortunately, this code doesn't work, because it lacks two functions,
> `get-current-env` and `extends-env`.
>

These are not available since static lexical scope makes it possible for
the compiler to determine where
a variable is stored at compile time. Therefore an explicit environment is
not needed.
(See "early binding" vs "late binding").


> Is there any way to work around this issue?
>


> I have searched Racket's document. Racket has namespaces that are very
> similar to the environment here.
>
> But it seems that `current-namespace` can not get binding (e.g. Just) and
> `namespace-set-variable-value!` is a mutable function which is not suitable
> as well.
>

Namespaces are "environment-like" but contain only top-level variables.

Could someone give me some advice?
> Or we can modify the code above to make it work in Racket.
>

Since this for educational/fun use and not practical, I suggest using a
Scheme interpreter where the environments
are explicit.  Then you can easily add `get-current-env` and `extends-env`
yourself.

One option is the interpreter page LiSP (Lisp in Small Pieces) where an
interpreter for fexprs is discussed
with full working code.

/Jens Axel
https://racket-stories.com

-- 
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/CABefVgwBO%2BMG6SH66mHM_-LTsxpWTBsTu-%3DKSQ-skwjmUQvBOA%40mail.gmail.com.


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

[racket-users] About FEXPRS

2020-06-07 Thread Hendrik Boom
On Sun, Jun 07, 2020 at 08:09:40PM +0800, Siyuan Chen wrote:
...
...
> 
> There is an alternative of Lisp macros called FEXPRs, see
> https://en.wikipedia.org/wiki/Macro_(computer_science)#Early_Lisp_macros
> 
> > Early Lisp macros
> > Before Lisp had macros, it had so-called FEXPRs, function-like operators
> whose inputs were not the values computed by the arguments but rather the
> syntactic forms of the arguments, and whose output were values to be used
> in the computation. In other words, FEXPRs were implemented at the same
> level as EVAL, and provided a window into the meta-evaluation layer. This
> was generally found to be a difficult model to reason about effectively.

This wasn't just a feature for the expert user; it was the way basic 
primitives like 'quote', 'cond', and 'let' were implemented in the 
lisp 1.5 interpreter; the actual interpreting code being written in 
assembler (or Lisp, if it wasn't an utterly necessary primitive).

-- hendrik

> 
> More information, see https://en.wikipedia.org/wiki/Fexpr
...
...

-- 
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/20200607160227.bmwnuh5cg4kvkren%40topoi.pooq.com.


Re: [racket-users] Re: [racket] Web Framework Benchmarks

2020-06-07 Thread Bogdan Popa
Small update on this: I've updated the benchmarks to run multiple Racket
processes with an Nginx load balancer in front.  After some tuning[1], here
is what the results look like on my 12 core AMD Ryzen 9 3900 server:

https://www.techempower.com/benchmarks/#section=test=669bfab7-9242-4c26-8921-a4fe9ccd8530=ph=composite=2

50k/s is a respectable number for the plaintext benchmark IMO and we
could get it to go higher if we could ditch Nginx or spend more time
improving the server's internals, as Sam suggested.

The `racket-perf' benchmark is for a branch[2] that I have where I've made
some small improvements to the server's internals.

[0]: https://github.com/TechEmpower/FrameworkBenchmarks/pull/5727
[1]: https://github.com/TechEmpower/FrameworkBenchmarks/pull/5737
[2]: https://github.com/racket/web-server/pull/94

-- 
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/m2o8pupyge.fsf%40192.168.0.142.


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
>  

[racket-users] Is it possible to simulate FEXPRs in Racket?

2020-06-07 Thread Siyuan Chen
Dear all,

** Note that this question is not for practical programming, but just play
for fun.**

I want to implement Maybe monad in Racket.

The following code works.

```
(struct Just (a)
  #:transparent)
(struct Nothing ()
  #:transparent)

(define (bigger-than-two n)
(if (> n 2)
(Just n)
(Nothing)))

(define (>>= mx f)
  (match mx
[(Nothing) (Nothing)]
[(Just x) (f x)]))


(>>= (bigger-than-two 4)
  (λ (x)
(>>= (bigger-than-two 5)
  (λ (y)
(Just (+ x y))
```

The disadvantage of this implementation is that it doesn't look nice.

So I want to implement do notation.

One way to implement do notation is by using Lisp macro, but I don't want
to use macro.

There is an alternative of Lisp macros called FEXPRs, see
https://en.wikipedia.org/wiki/Macro_(computer_science)#Early_Lisp_macros

> Early Lisp macros
> Before Lisp had macros, it had so-called FEXPRs, function-like operators
whose inputs were not the values computed by the arguments but rather the
syntactic forms of the arguments, and whose output were values to be used
in the computation. In other words, FEXPRs were implemented at the same
level as EVAL, and provided a window into the meta-evaluation layer. This
was generally found to be a difficult model to reason about effectively.

More information, see https://en.wikipedia.org/wiki/Fexpr

Therefore, I attempt to use fexpr to simulate macro.

The following code simulates fexpr by `eval` to implement Maybe monad.

```
(struct Just (a)
  #:transparent)
(struct Nothing ()
  #:transparent)

(define (bigger-than-two n)
(if (> n 2)
(Just n)
(Nothing)))

(define (do env binds return)
  (match binds
[nil
 (eval return env)]
[`((,var ,e) ,rest-binds)
 (match (eval (e env))
   [(Nothing) (Nothing)]
   [(Just x) (do (extends-env env var x) rest-binds return)])]))

(do (get-current-env)
(list '[x (bigger-than-two 4)]
  '[y (bigger-than-two 5)])
  '(Just (+ x y)))
```

Unfortunately, this code doesn't work, because it lacks two functions,
`get-current-env` and `extends-env`.

Is there any way to work around this issue?

I have searched Racket's document. Racket has namespaces that are very
similar to the environment here.

But it seems that `current-namespace` can not get binding (e.g. Just) and
`namespace-set-variable-value!` is a mutable function which is not suitable
as well.

Could someone give me some advice?
Or we can modify the code above to make it work in Racket.

Very thanks.

Best regards,
Siyuan Chen

-- 
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/CAHWTsYnhHCwg1gQuZVG%2BjnwLmnC3_8UK4L4n98JpTJ9PWePKxg%40mail.gmail.com.


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] identifier used out of context

2020-06-07 Thread Alexis King
> On Jun 7, 2020, at 17:44, Sorawee Porncharoenwase  
> wrote:
> 
> Wow, so block is currently buggy?!
> 

This issue isn’t with `block`, per se (though `block` could cooperate more 
nicely with definition context expansion to avoid this problem). You can 
reproduce it without any first-class definition contexts at all:

#lang racket
(define-syntax-rule (m) (displayln 'old))
(let ()
  (m)
  (define-syntax-rule (m) 'new)
  (void))

Arguably, the real issue is the mechanism behind Check Syntax. Check Syntax 
collects information about uses and bindings from the fully-expanded program, 
but that is not straightforward for macro uses and local macro bindings, since 
those go away after expansion. So the expander annotates the program with 
information about disappeared identifier uses and disappeared local bindings 
using the 'origin, 'disappeared-use, and 'disappeared-binding syntax properties.

The hope is that the binding structure of the source program can be 
reconstructed from the fully-expanded program by inspecting identifiers’ 
scopes. This seems plausible, since the scopes of a fully-expanded program 
dictate the binding structure of runtime variables by definition. However, this 
example reveals a flaw in that logic: resolution of macro bindings also 
involves a temporal component, since the compile-time binding table evolves as 
the program is expanded.

Frankly, this temporal dependency is unsatisfying. For runtime bindings, we 
enjoy predictable recursive definition contexts and inter-module lexical 
binding, courtesy of the module system. But to paraphrase Matthew, resolution 
of compile-time bindings is “distressingly like the top level,” since it 
requires interleaving of expansion and evaluation in a similar way.

I think this suggests that perhaps there is something fundamentally incomplete 
in our model of macroexpansion. However, it seems impossible to solve this 
problem without somehow restricting the macro language: the status quo allows 
macros to both (a) expand to absolutely anything via arbitrary procedural logic 
and (b) perform arbitrary side-effects, which allows them to observe expansion 
order. A more restrictive model could require macros to declare more 
information up front (which would allow the macroexpander to learn more about 
the binding structure of a program without fully expanding macros) or could 
provide access to state through restricted channels in such a way that the 
expander could “speculatively” expand a macro, then go back later and change 
its mind.

Of course, these would both require radical, deeply incompatible changes to the 
Racket macro system, so I do not expect them to actually be implemented! But 
perhaps they can be food for thought.

Alexis

-- 
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/D48BCCBB-AE1F-47CC-93E8-B90D1129E169%40gmail.com.


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 ()
>>> [(_