17.3.6 Module-Handling Configuration

► |  | The Racket Guide

1 | Welcome to Racket
2 | Racket Essentials
3 | Built-In Datatypes
4 | Expressions and Definitions
5 | Programmer-Defined Datatypes
6 | Modules
7 | Contracts
8 | Input and Output
9 | Regular Expressions
10 | Exceptions and Control
11 | Iterations and Comprehensions
12 | Pattern Matching
13 | Classes and Objects
14 | Units
15 | Reflection and Dynamic Evaluation
16 | Macros
17 | Creating Languages
18 | Concurrency and Synchronization
19 | Performance
20 | Parallelism
21 | Running and Creating Executables
22 | More Libraries
23 | Dialects of Racket and Scheme
24 | Command-Line Tools and Your Editor of Choice
| Bibliography
| Index

► | 17 | Creating Languages

17.1 | Module Languages
17.2 | Reader Extensions
17.3 | Defining new #lang Languages

▼ | 17.3 | Defining new #lang Languages

17.3.1 | Designating a #lang Language
17.3.2 | Using #lang reader
17.3.3 | Using #lang s-exp syntax/ module-reader
17.3.4 | Installing a Language
17.3.5 | Source-Handling Configuration
17.3.6 | Module-Handling Configuration

top contents ← prev up next →

##### 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.

top contents ← prev up next →