Thanks Sam.
I ended up finding another alternative, which is to replace the
set!-followed-by-define with define-values:
(define-values (name.r ...) (values (lambda (param ...) body ...) ...))
One more related question (though given the hopelessness, I'd understand if
there isn't a great answer):
Before writing this multi-definition syntax, I originally wrote a
single-item version that expanded to a single pair of syntax wrapper and
value definition:
(define-syntax (issue-syntax-single stx)
(syntax-case stx ()
((_ (name param ...) body ...)
#'(begin (define-syntax (name stx)
(syntax-case stx ()
((_ . args) #'(name.r . args))
(_ #'name.r)))
(define name.r (lambda (param ...) body ...))))))
In fact, I didn't expect to need a multi-definition version. The hope was
that I could define these one-by-one, even when they are
mutually-recursive. This does work in a module, but fails at the
top-level. I also tried the forward-declaration you suggest, but get the
same error.
> (define-syntaxes (foo bar) (values)) ; attempted forward-declaration
(did I do this correctly?)
> (issue-syntax-single (foo x) (bar x 1 2))
> (issue-syntax-single (bar a b c) `(bar: ,a ,b ,c))
> (foo 'the-top-level-is-hopeless)
; bar: undefined;
; cannot reference an identifier before its definition
; in module: top-level
; [,bt for context]
> ,bt
; bar: undefined;
; cannot reference an identifier before its definition
; in module: top-level
; context...:
; body of top-level
; readline-input:8:33: name.r
; /Applications/Racket v8.0/share/pkgs/xrepl-lib/xrepl/xrepl.rkt:1493:0
; /Applications/Racket v8.0/collects/racket/repl.rkt:11:26
Is there another workaround that would help the single-item version?
On Monday, June 28, 2021 at 9:51:32 AM UTC-4 Sam Tobin-Hochstadt wrote:
> This is indeed an issue where "the top-level is hopeless" is the problem
> [1].
>
> However, there's a better work-around. You can write `(define-syntaxes
> (name.r ...) (values))` to forward-declare all those names, and then
> the subsequent definitions will work correctly.
>
> Sam
>
> [1] https://lists.racket-lang.org/users/archive/2005-November/010350.html
> is a good short description of the problem here.
>
> On Fri, Jun 25, 2021 at 5:34 PM Greg Rosenblatt <[email protected]>
> wrote:
> >
> > I've encountered an identifier binding order issue that only manifests
> in the REPL. My current workaround is to use forward definitions followed
> by set!s. I've heard rumors that the top-level is hopeless, but I'd like to
> try and make this work without unnecessary workarounds, if possible.
> >
> >
> > To demonstrate the issue, I've defined a syntax transformer that binds
> temporary names to procedures, and defines wrapper syntax transformers for
> referencing these procedures.
> >
> > This syntax works fine within a module, or other non-top-level
> definition context. But when used at the top-level, I get an unbound
> identifier error as the first procedure body is being expanded. The first
> procedure references the second via the wrapper.
> >
> >
> > ;; issue.rkt
> > #lang racket/base
> > (provide issue-syntax)
> > (require (for-syntax racket/base))
> >
> > (define-syntax (issue-syntax stx)
> > (syntax-case stx ()
> > ((_ ((name param ...) body ...) ...)
> > (with-syntax (((name.r ...) (generate-temporaries #'(name ...))))
> > #'(begin (define-syntax (name stx)
> > (syntax-case stx ()
> > ((_ . args) #'(name.r . args))
> > (_ #'name.r))) ...
> > (define name.r (lambda (param ...) body ...)) ...)))))
> > ;; eof
> >
> >
> > > racket
> > Welcome to Racket v8.0 [cs].
> > > (require "issue.rkt")
> > > (let ()
> > (issue-syntax
> > ((foo x) (bar x 1 2)) ; note the reference to bar
> > ((bar a b c) `(bar: ,a ,b ,c)))
> > (foo 'is-the-top-level-hopeless?))
> > (bar: is-the-top-level-hopeless? 1 2)
> > > (issue-syntax
> > ((foo x) (bar x 1 2)) ; note the reference to bar
> > ((bar a b c) `(bar: ,a ,b ,c)))
> > ; bar4: unbound identifier;
> > ; also, no #%top syntax transformer is bound
> > ; in: bar4
> > ; [,bt for context]
> > > ,bt
> > ; bar4: unbound identifier;
> > ; also, no #%top syntax transformer is bound
> > ; in: bar4
> > ; context...:
> > ; /Applications/Racket v8.0/share/pkgs/xrepl-lib/xrepl/xrepl.rkt:1493:0
> > ; /Applications/Racket v8.0/collects/racket/repl.rkt:11:26
> >
> >
> > I can work around this issue by altering issue-syntax to forward-define
> names before using set! to initialize them:
> >
> > (define-syntax (issue-syntax stx)
> > (syntax-case stx ()
> > ((_ ((name param ...) body ...) ...)
> > (with-syntax (((name.r ...) (generate-temporaries #'(name ...))))
> > #'(begin (define-syntax (name stx)
> > (syntax-case stx ()
> > ((_ . args) #'(name.r . args))
> > (_ #'name.r))) ...
> > (define name.r #f) ... ; forward definitions
> > (set! name.r (lambda (param ...) body ...)) ...)))))
> >
> >
> > Is there a better alternative?
> >
> > --
> > 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/cd8675e8-95d0-4552-badc-d4ec7a430109n%40googlegroups.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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/f6515c74-86d0-48cd-a242-d56f719cd1f8n%40googlegroups.com.