Language-provided bindings and arrows in DrRacket

58 views
Skip to first unread message

Dupéron Georges

unread,
Dec 3, 2016, 10:00:21 PM12/3/16
to Racket Users
I'm writing a meta-language (a small extension of scribble/lp2), which delegates to a second language. I am using the neat trick suggested to me by Alex Knauth [1], but I have trouble getting the arrows to be drawn in DrRacket for language "built-ins".

A boiled down version of the language file "MyLang.rkt" follows:

#lang racket
(provide (rename-out [my-module-begin #%module-begin]))
(define-syntax (my-module-begin stx)
(syntax-case stx ()
[(_ real-lang body)
(syntax-case (local-expand #'(module m real-lang body) 'top-level (list)) ()
[(module nm lng (#%plain-module-begin . body2))
#'(#%plain-module-begin
;; use (only lng) to avoid conflicts with other require
(#%require (only lng))
. body2)])]))

It is used by "m.rkt":

(module m "MyLang.rkt" ;; MyLang acts as a meta-language
racket/base ;; which delegates to this language
(displayln "Hello")) ;; using this body

The problem I have is that "displayln" is highlighted with a blue-green background in DrRacket, indicating that it is provided by the module's language, but there is no arrow drawn from the "racket/base" just above.

If I change the last line of "MyLang.rkt" to put the fully-expanded module as a submodule (instead of merely extracting the contents of the #%plain-module-begin), then the arrow gets drawn:

#'(#%plain-module-begin (module nm lng (#%plain-module-begin . body)))

What conditions must be met for the arrow to be drawn?

[1] http://stackoverflow.com/a/38032107/324969

Dupéron Georges

unread,
Dec 3, 2016, 10:11:58 PM12/3/16
to Racket Users
I made a copy-paste mistake, the replacement for the last line of "MyLang.rkt" should use "body2" instead of "body":

#'(#%plain-module-begin (module nm lng (#%plain-module-begin . body2)))

Robby Findler

unread,
Dec 3, 2016, 10:18:44 PM12/3/16
to Dupéron Georges, Racket Users
The fully expanded form of the original program doesn't have a require
that brings in displayln? So I'm not sure how Check Syntax could know
to draw an arrow.

Robby
> --
> 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.
> For more options, visit https://groups.google.com/d/optout.

Dupéron Georges

unread,
Dec 4, 2016, 10:18:30 AM12/4/16
to Racket Users, jahvascr...@gmail.com
Le dimanche 4 décembre 2016 04:18:44 UTC+1, Robby Findler a écrit :
> The fully expanded form of the original program doesn't have a require
> that brings in displayln?

Indeed, if I use (#%require lng) the arrows get drawn.

However, the body can require libraries which shadow some of the language-provided bindings, e.g. (require type-expander) shadows some of the bindings imported by #lang typed/racket. I therefore use (#%require (only lng)) to make sure the lng module is available, without creating potential conflicts with other required modules.

I was hoping there would be some trick similar to disappeared-use and disappeared-bindings that would help me solve this problem. I suppose I could apply a 'disappeared-binding property to the "racket/base" on the second line, using a list containing every binding imported by the "module language".

Dupéron Georges

unread,
Dec 4, 2016, 10:27:54 AM12/4/16
to Racket Users, jahvascr...@gmail.com
I think I found a solution which allows me to inject the (#%require lng) without causing conflicts with other required module: applying an extra scope to the whole body makes the other (require) forms more specific, and they can shadow bindings imported by (#%require lng).

Here is the modified "MyLang.rkt":

#lang racket
(provide (rename-out [my-module-begin #%module-begin]))
(define-syntax (my-module-begin stx)
(syntax-case stx ()
[(_ real-lang body)
(syntax-case (local-expand #'(module m real-lang body) 'top-level (list)) ()

[(module nm lng (#%plain-module-begin . body2))
#`(#%plain-module-begin
(#%require lng)
. #,((make-syntax-introducer) #'body2))])]))

And here's an example file using it:

(module m "MyLang.rkt"
;; delegates to this language:
typed/racket/base
;; body:
(begin
(require racket/set)
(displayln ;; arrow successfully drawn to typed/racket/base
(set ;; arrow successfully drawn to racket/set
"Hello"))))

Without the extra scope, I would get this error because racket/set shadows these bindings imported by typed/racket/base:

module: identifier already imported from a different source in:
for/set
racket/set
typed/racket/base

My problem seems solved, but if this extra-scope trick has some unwanted consequences, I would definitely want to hear about them!

Alex Knauth

unread,
Dec 4, 2016, 11:47:21 AM12/4/16
to Dupéron Georges, Racket Users
On Dec 4, 2016, at 10:27 AM, Dupéron Georges <jahvascr...@gmail.com> wrote:

I think I found a solution which allows me to inject the (#%require lng) without causing conflicts with other required module: applying an extra scope to the whole body makes the other (require) forms more specific, and they can shadow bindings imported by (#%require lng).

A nested scope seems like the correct solution. The macro expander does something similar with module body's, but it creates a pair of scopes for the body. I'm not sure whether you would need to do the same...


I can't see any unwanted consequences of this approach, but I also don't know much about how scopes work with requires.

Alex Knauth

Here is the modified "MyLang.rkt":

#lang racket
(provide (rename-out [my-module-begin #%module-begin]))
(define-syntax (my-module-begin stx)
 (syntax-case stx ()
   [(_ real-lang body)
    (syntax-case (local-expand #'(module m real-lang body) 'top-level (list)) ()
      [(module nm lng (#%plain-module-begin . body2))
       #`(#%plain-module-begin
            (#%require lng)
            . #,((make-syntax-introducer) #'body2))])]))

Reply all
Reply to author
Forward
0 new messages