Several times now, I've run into one or another form of the following problem:
Say I want to build primitives to
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 570512 1 module j 570515 2 macro 570719 3 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 571247 1 module j 571250 2 macro 571455 3 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 576854 1 module j 576857 2 module 577056 3 module j 577059 4 module 577150 5 module h 577153 6 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 572388 1 module j 572391 2 module 572596 3 module j 572599 4 macro 572697 5 module 572682 6 module h 572685
What's going on here? How do I fix this?
Eric
On Jun 3, 2019, at 11:52 AM, Eric Griffis <ded...@gmail.com> wrote:
Several times now, I've run into one or another form of the following problem:
Say I want to build primitives to
- declare an "interface" as a list of names, and
- implement and use those names at run time in a limited scope