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 ()
[(_ body ...)
#`(let ([acc '()])
#,@(map (do-it gs ctx) (syntax->list #'(body ...)))
(reverse acc))]))
($list 1
(define x 2)
x)
There are problems though. If I change define
to define2
as follows:
(define-syntax-rule (define2 x y)
(define-values (x) y))
($list 1
(define2 x 2)
x)
Then I get the “identifier used out of context” error. This doesn’t make sense to me at all. My define2
should be very similar to define
…
There’s also another weird problem:
($list 1
(define-syntax (x stx) #'2)
x)
The above works perfectly, but by wrapping x
with #%expression
, I get the “identifier used out of context” error again.
($list 1
(define-syntax (x stx) #'2)
(#%expression x))
What did I do wrong?
Thanks!
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.
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.
--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/748eead8-76b9-43bc-94da-2c832ba8896do%40googlegroups.com.
(define-syntax-rule (m) 'old)
(let () ($list (m)) (define-syntax-rule (m) 'new))
internal-definition-context-track
is needed.($list
(define-syntax-rule (m) 5)
(m))
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 intoletrec-syntaxes+values
, so the bindings don’t actually disappear. So I am curious whyinternal-definition-context-track
is needed.Thanks again.
To unsubscribe from this group and stop receiving emails from it, send an email to racket...@googlegroups.com.
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.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/ae981bda-94d3-43d2-ae23-a41f5160aa0ao%40googlegroups.com.
#lang racket
(require racket/block)
(define-syntax-rule (m) (displayln 'old))
(let () (block (m)) (define-syntax-rule (m) 'new) (void))
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 ofm
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/ae981bda-94d3-43d2-ae23-a41f5160aa0ao%40googlegroups.com.
Wow, so block
is currently buggy?!
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/30972297-14f6-4cf9-8821-de5753f3dacfo%40googlegroups.com.
On Jun 7, 2020, at 17:44, Sorawee Porncharoenwase <sorawe...@gmail.com> wrote:Wow, so
block
is currently buggy?!
Wow, so
block
is currently buggy?!
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/30972297-14f6-4cf9-8821-de5753f3dacfo%40googlegroups.com.