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:
(module module-name expander
other-expressions
to-expand
and-evaluate ...)
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):
(module my-module br
(* 6 7))
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:
(module mod-name br
(format-datum '(hello world)))
'(hello world)
But this module won’t run, because format-datum is not provided by the racket language:
(module mod-name racket
(format-datum '(hello world)))
format-datum: unbound identifier in module in: format-datum
But that can be fixed with a require, and this version will run:
(module mod-name racket
(require br)
(format-datum '(hello world)))
'(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:
#lang br
(* 6 7)
(module my-module 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:
#lang br
(module tired br
(sleep 10000)
(module awake br
(define greeting "Good morning")
(provide greeting)
(module also-tired br
(sleep 10000))))
(require (submod "." tired awake))
greeting ; "Good morning"
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:
#lang br
(provide launch-rocket)
(define (launch-rocket) (displayln "whee"))
(displayln "4, 3, 2, 1 ...")
(module+ main
(launch-rocket))
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:
#lang br
(module rocket br
(provide launch-rocket)
(define (launch-rocket) (displayln "whee"))
(displayln "4, 3, 2, 1 ...")
(module+ main
(launch-rocket)))
(require 'rocket)
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.
#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