Several times now, I've run into one or another form of the following
problem:

Say I want to build primitives to

   1. declare an "interface" as a list of names, and
   2. implement and use those names at run time in a limited scope

Concretely, I want to run the following code:

(interface Speaker say speak)
(implement Speaker displayln (say 'hello) speak)

If I put these lines at the end of a file that implements the two forms, it
should (displayln 'hello) when I run it.

Here is the interface macro:

(define-syntax (interface stx)
  (syntax-case stx ()
    [(_ id member-id ...) #'(define-syntax id #'(member-id ...))]))

The implement macro is trickier. A naive implementation looks like this:

(define-syntax (implement stx)
  (syntax-case stx ()
    [(_ class-id def ... expr)
     (with-syntax ([(id ...) (syntax-e (syntax-local-value #'class-id))])
       #'(letrec ([id def] ...) expr))]))

It fails with the following message:

; /tmp/j.rkt:44:30: say: unbound identifier;   in: say;   context...:;
   #(570423 use-site) [common scopes];   other binding...:;    local;
  #(570422 macro) [common scopes];   common scopes...:;    #(570223
module) #(570226 module j) #(570426 local) #(570427 intdef);
#(570428 local)

Incorporating the debug-scopes package's +scopes macro shows this:

(letrec⁰˙˙¹
 ((say⁰˙˙¹ displayln⁰˙˙³) (speak⁰˙˙¹ (say⁰˙˙³ (quote⁰˙˙³ hello⁰˙˙³))))
 speak⁰˙˙³)ˢˡⁱ⁼²⁺ᵘˢᵉ⁼³0 module   5705121 module j 5705152 macro
5707193 use-site 570720

For reasons I don't yet fully comprehend, it just works out if I use
syntax-local-introduce on the id's, so +scopes gives me this:

(letrec⁰˙˙¹
 ((say⁰˙˙³ displayln⁰˙˙³) (speak⁰˙˙³ (say⁰˙˙³ (quote⁰˙˙³ hello⁰˙˙³))))
 speak⁰˙˙³)ˢˡⁱ⁼²⁺ᵘˢᵉ⁼³0 module   5712471 module j 5712502 macro
5714553 use-site 571456

But if the interface and implement invocations are not in the same file as
their implementations, it breaks with a similar error:

; /tmp/h.rkt:5:30: say: unbound identifier;   in: say;   context...:;
  #(572682 module) [common scopes];   other binding...:;    local;
#(572388 module) #(572391 module j) #(572596 module);    #(572599
module j) [common scopes];   common scopes...:;    #(572685 module h)
#(572700 local) #(572701 intdef) #(572702 local)

In this situation, +scopes gives:

(letrec⁰˙˙³
 ((say⁴˙˙⁵ displayln⁴˙˙⁶) (speak⁴˙˙⁵ (say⁴˙˙⁶ (quote⁴˙˙⁶ hello⁴˙˙⁶))))
 speak⁴˙˙⁶)ˢˡⁱ⁼⁶⁺ᵘˢᵉ⁼0 module   5768541 module j 5768572 module
5770563 module j 5770594 module   5771505 module h 5771536 macro
577173

If I move the interface invocation back into the original file and keep the
implement invocation in a separate file, I get the same error but +scopes
gives something slightly different:

(letrec⁰˙˙³
 ((say⁰˙˙⁴ displayln⁴˙˙⁶) (speak⁰˙˙⁴ (say⁴˙˙⁶ (quote⁴˙˙⁶ hello⁴˙˙⁶))))
 speak⁴˙˙⁶)ˢˡⁱ⁼⁴⁺ᵘˢᵉ⁼0 module   5723881 module j 5723912 module
5725963 module j 5725994 macro    5726975 module   5726826 module h
572685

What's going on here? How do I fix this?

Eric

-- 
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/CAORuSUz_v5jYSFQetnuLb6haNx8Hwo0CqR0Bm-jCJO0DT7Bz6w%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to