When using the longhand module form for writing modules, the module path that is specified after the new module’s name provides the initial imports for the module. Since the initial-import module determines even the most basic bindings that are available in a module’s body, such as require , the initial import can be called a module language.
The most common module languages are racket or racket/base, but you can define your own module language by defining a suitable module. For example, using provide subforms like all-from-out , except-out , and rename-out , you can add, remove, or rename bindings from racket to produce a module language that is a variant of racket:
+The module Form introduces the longhand module form.
[(0)"love"][(1)"fifteen"][(2)"thirty"][(3)"forty"]))'("love" "thirty")
If you try to remove too much from racket in defining your own module language, then the resulting module will no longer work right as a module language:
eval:2:0: module: no #%module-begin binding in the module's
language
in: (module identity (quote just-lambda) (lambda (x) x))
The #%module-begin form is an implicit form that wraps the body of a module. It must be provided by a module that is to be used as module language:
#<procedure>
The other implicit forms provided by racket/base are #%app for function calls, #%datum for literals, and #%top for identifiers that have no binding:
10
Implicit forms such as #%app can be used explicitly in a module, but they exist mainly to allow a module language to restrict or change the meaning of implicit uses. For example, a lambda-calculus module language might restrict functions to a single argument, restrict function calls to supply a single argument, restrict the module body to a single expression, disallow literals, and treat unbound identifiers as uninterpreted symbols:
'id))'z
eval:4:0: lambda: use does not match pattern: (lambda (x)
expr)
in: (lambda (x y) x)
eval:5:0: #%module-begin: use does not match pattern:
(#%module-begin e)
in: (#%module-begin (lambda (x) x) (lambda (y) (y y)))
eval:6:0: #%app: use does not match pattern: (#%app e1 e2)
in: (#%app x x x)
10)eval:7:0: #%datum: no
in: (#%datum . 10)
Module languages rarely redefine #%app , #%datum , and #%top , but redefining #%module-begin is more frequently useful. For example, when using modules to construct descriptions of HTML pages where a description is exported from the module as page, an alternate #%module-begin can help eliminate provide and quasiquoting boilerplate, as in "html.rkt":
"html.rkt"
now)
Using the "html.rkt" module language, a simple web page can be described without having to explicitly define or export page and starting in quasiquote d mode instead of expression mode:
> page'(html (title "Queen of Diamonds") (p "Updated: " "2025-08-16"))
Implementing a language at the level of #lang is more complex than declaring a single module, because #lang lets programmers control several different facets of a language. The s-exp language, however, acts as a kind of meta-language for using a module language with the #lang shorthand:
form...
is the same as
where name is derived from the source file containing the #lang program. The name s-exp is short for “S-expression,” which is a traditional name for Racket’s reader-level lexical conventions: parentheses, identifiers, numbers, double-quoted strings with certain backslash escapes, and so on.
Using #lang s-exp, the lady-with-the-spinning-head example from before can be written more compactly as:
(title"Queen of Diamonds")(p"Updated: ",(now))
Later in this guide, Defining new #lang Languages explains how to define your own #lang language, but first we explain how you can write reader-level extensions to Racket.