17.1 Module Languages

► |  | 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.1 | Module Languages

17.1.1 | Implicit Form Bindings
17.1.2 | Using #lang s-exp

On this page:

17.1.1`` Implicit Form Bindings
17.1.2`` Using #lang s-exp

top ← prev up next →

#### 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: " "2019-01-30"))

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

top ← prev up next →