17.3.6 Module-Handling Configuration
Suppose that the file "death-list-5.rkt" contains
"death-list-5.rkt"
#lang racket (list "O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")
If you require "death-list-5.rkt" directly, then it prints the list in the usual Racket result format:
> (require "death-list-5.rkt") '("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")
However, if "death-list-5.rkt" is required by a "kiddo.rkt" that is implemented with scheme instead of racket:
"kiddo.rkt"
#lang scheme (require "death-list-5.rkt")
then, if you run "kiddo.rkt" file in DrRacket or if you run it directly with racket, "kiddo.rkt" causes "death-list-5.rkt" to print its list in traditional Scheme format, without the leading quote:
("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")
The "kiddo.rkt" example illustrates how the format for printing a result value can depend on the main module of a program instead of the language that is used to implement it.
More broadly, certain features of a language are only invoked when a module written in that language is run directly with racket (as opposed to being imported into another module). One example is result-printing style (as shown above). Another example is REPL behavior. These features are part of what’s called the run-time configuration of a language.
Unlike the syntax-coloring property of a language (as described in Source-Handling Configuration), the run-time configuration is a property of a module per se as opposed to a property of the source text representing the module. For that reason, the run-time configuration for a module needs to be available even if the module is compiled to bytecode form and the source is unavailable. Therefore, run-time configuration cannot be handled by the get-info function we’re exporting from the language’s parser module.
Instead, it will be handled by a new configure-runtime submodule that we’ll add inside the parsed module form. When a module is run directly with racket, racket looks for a configure-runtime submodule. If it exists, racket runs it. But if the module is imported into another module, the 'configure-runtime submodule is ignored. (And if the configure-runtime submodule doesn’t exist, racket just evaluates the module as usual.) That means that the configure-runtime submodule can be used for any special setup tasks that need to happen when the module is run directly.
Going back to the literal language (see Source-Handling Configuration), we can adjust the language so that directly running a literal module causes it to print out its string, while using a literal module in a larger program simply provides data without printing. To make this work, we will need an extra module. (For clarity here, we will implement this module as a separate file. But it could equally well be a submodule of an existing file.)
.... (the main installation or the user’s space) |- "literal" |- "main.rkt" (with reader submodule) |- "show.rkt" (new)
The "literal/show.rkt" module will provide a show function to be applied to the string content of a literal module, and also provide a show-enabled parameter that controls whether show actually prints the result.
The new configure-runtime submodule in "literal/main.rkt" will set the show-enabled parameter to #t. The net effect is that show will print the strings that it’s given, but only when a module using the literal language is run directly (because only then will the configure-runtime submodule be invoked).
These changes are implemented in the following revised "literal/main.rkt":
"literal/main.rkt"
#lang racket (module reader racket (require syntax/strip-context) (provide (rename-out [literal-read read] [literal-read-syntax read-syntax]) get-info) (define (literal-read in) (syntax->datum (literal-read-syntax #f in))) (define (literal-read-syntax src in) (with-syntax ([str (port->string in)]) (strip-context #'(module anything racket (module configure-runtime racket (require literal/show) (show-enabled #t)) (require literal/show) (provide data) (define data 'str) (show data))))) (define (get-info in mod line col pos) (lambda (key default) (case key [(color-lexer) (dynamic-require 'syntax-color/default-lexer 'default-lexer)] [else default]))))
Then the "literal/show.rkt" module must provide the show-enabled parameter and show function:
"literal/show.rkt"
#lang racket (provide show show-enabled) (define show-enabled (make-parameter #f)) (define (show v) (when (show-enabled) (display v)))
With all of the pieces for literal in place, try running the following variant of "tuvalu.rkt" directly and through a require from another module:
"tuvalu.rkt"
#lang literal Technology! System! Perfect!
When run directly, we’ll see the result printed like so, because our configure-runtime submodule will have set the show-enabled parameter to #t:
Technology!
System!
Perfect!
But when imported into another module, printing will be suppressed, because the configure-runtime submodule will not be invoked, and therefore the show-enabled parameter will remain at its default value of #f.