A module is the basic organizational unit of code in Racket. Three simple rules:
All program code is contained in a module, through the use of module or one of its variants. A module expression includes a name, an expander, and a body containing other expressions:
For instance, the code below creates a module named my-module, using the br expander, with one expression inside (in an exception to the usual custom, run these samples in DrRacket without a #lang br line at the top, or on the REPL):
1 | 42
|
The expander supplies the initial bindings that are available to expressions inside the module. If these expressions refer to bindings not provided by the expander, or not otherwise imported within the module (with require), then the module will not run.
For instance, this module will run, because format-datum is provided by the br language:
1 2 | (module mod-name br (format-datum '(hello world))) |
1 | '(hello world) |
But this module won’t run, because format-datum is not provided by the racket language:
1 2 | (module mod-name racket (format-datum '(hello world))) |
1 | format-datum: unbound identifier in module in: format-datum |
But that can be fixed with a require, and this version will run:
1 2 3 | (module mod-name racket (require br) (format-datum '(hello world))) |
1 | '(hello world) |
Modules are “lazy” in the sense that the code inside a module never runs until that module is explicitly requested (say, by a require from elsewhere—see importing and exporting).
The #lang line is just a disguised module expression. Every source file with a #lang line expands to a single module expression at the top level. For instance, these two programs are the same, and will both evaluate to 42:
1 2 | #lang br (* 6 7) |
This is why in Racket lingo, a source file is itself called a module.
“What about expressions entered at a REPL?” These expressions are treated as if they belong to the top-level module of the language being used.
Modules can be nested inside each other to create hierarchies of submodules. They can be nested to any depth, but typically only descend one level. Submodules are defined with the same module syntax as regular modules. Submodules have two additional rules:
A submodule can require its enclosing module, or vice versa, but not both.
Contrary to Racket’s usual evaluation rules, a submodule does not automatically run when its enclosing module runs; likewise, running a submodule does not automatically run its enclosing module.
This last rule is important, because it extends the “lazy” behavior in a nicely magical way: even when modules are nested, they behave like totally independent programs.
In the example below, the awake submodule has an enclosing tired module and a nested also-tired submodule that will each take a long time to run. But with a (require (submod ...)) expression, we can run the awake submodule without triggering the others:
submod allows access to submodules through a pathlike notation. In this case, "." means “start in the current module”, and tired awake is the “path” to the submodule.
module+ defines a module that adopts all the bindings of the surrounding module. It can still define and provide additional bindings. It can also be defined in separate pieces: all module+ expressions with the same name will be combined into a single submodule.
module* defines a module that can require its enclosing module (but not vice versa).
Any code in a main submodule will be evaluated when the enclosing module is run directly in DrRacket or from the command line—but not when the module is imported with require. This allows a module to provide bindings but specify additional behavior for when it’s invoked directly.
For instance, this source file prints a countdown and then also calls launch-rocket, because it’s in the main submodule:
1 2 | 4, 3, 2, 1 ... whee |
But when the same code is wrapped in a submodule and imported with require, the main submodule doesn’t run:
1 | 4, 3, 2, 1 ... |
It’s common in Racket to put unit tests inside a submodule called test (usually declared with module+, so it can use all the variables defined nearby). See unit testing.
When a language is specified on the #lang line, Racket will first try to invoke the reader for that language. The first place Racket looks for a reader is in a reader submodule of the source file indicated.
1 2 | #lang "yo.rkt" ; looks for reader in `(submod "yo.rkt" reader)` #lang br ; looks for reader in `(submod br reader)` |
Submodules in the Racket Guide
main and test submodules in the Racket Guide
Submodules in the Racket Reference