On this page:
17.1.1 Implicit Form Bindings
17.1.2 Using #lang s-exp

17.1 Module Languages🔗ℹ

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.

> (module raquet racket
    (provide (except-out (all-from-out racket) lambda)
             (rename-out [lambda function])))
> (module score 'raquet
    (map (function (points) (case points
                             [(0) "love"] [(1) "fifteen"]
                             [(2) "thirty"] [(3) "forty"]))
         (list 0 2)))
> (require 'score)

'("love" "thirty")

17.1.1 Implicit Form Bindings🔗ℹ

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:

> (module just-lambda racket
    (provide lambda))
> (module identity 'just-lambda
    (lambda (x) x))

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:

> (module just-lambda racket
    (provide lambda #%module-begin))
> (module identity 'just-lambda
    (lambda (x) x))
> (require 'identity)

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

> (module just-lambda racket
    (provide lambda #%module-begin
             ; ten needs these, too:
             #%app #%datum))
> (module ten 'just-lambda
    ((lambda (x) x) 10))
> (require 'ten)

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:

> (module lambda-calculus racket
    (provide (rename-out [1-arg-lambda lambda]
                         [1-arg-app #%app]
                         [1-form-module-begin #%module-begin]
                         [no-literals #%datum]
                         [unbound-as-quoted #%top]))
    (define-syntax-rule (1-arg-lambda (x) expr)
      (lambda (x) expr))
    (define-syntax-rule (1-arg-app e1 e2)
      (#%app e1 e2))
    (define-syntax-rule (1-form-module-begin e)
      (#%module-begin e))
    (define-syntax (no-literals stx)
      (raise-syntax-error #f "no" stx))
    (define-syntax-rule (unbound-as-quoted . id)
      'id))
> (module ok 'lambda-calculus
    ((lambda (x) (x z))
     (lambda (y) y)))
> (require 'ok)

'z

> (module not-ok 'lambda-calculus
    (lambda (x y) x))

eval:4:0: lambda: use does not match pattern: (lambda (x)

expr)

  in: (lambda (x y) x)

> (module not-ok 'lambda-calculus
    (lambda (x) x)
    (lambda (y) (y y)))

eval:5:0: #%module-begin: use does not match pattern:

(#%module-begin e)

  in: (#%module-begin (lambda (x) x) (lambda (y) (y y)))

> (module not-ok 'lambda-calculus
    (lambda (x) (x x x)))

eval:6:0: #%app: use does not match pattern: (#%app e1 e2)

  in: (#%app x x x)

> (module not-ok 'lambda-calculus
    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"

#lang racket
(require racket/date)
 
(provide (except-out (all-from-out racket)
                     #%module-begin)
         (rename-out [module-begin #%module-begin])
         now)
 
(define-syntax-rule (module-begin expr ...)
  (#%module-begin
   (define page `(html expr ...))
   (provide page)))
 
(define (now)
  (parameterize ([date-display-format 'iso-8601])
    (date->string (seconds->date (current-seconds)))))

Using the "html.rkt" module language, a simple web page can be described without having to explicitly define or export page and starting in quasiquoted mode instead of expression mode:

> (module lady-with-the-spinning-head "html.rkt"
    (title "Queen of Diamonds")
    (p "Updated: " ,(now)))
> (require 'lady-with-the-spinning-head)
> page

'(html (title "Queen of Diamonds") (p "Updated: " "2024-10-28"))

17.1.2 Using #lang s-exp🔗ℹ

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:

#lang s-exp module-name
form ...

is the same as

(module name module-name
  form ...)

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:

#lang s-exp "html.rkt"
 
(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.