structs via the module system. It allows
eDSL creators to ease their users into a
new language by reusing familiar syntax, but reinterpreted.
Consider lambda expressions, for
example. Suppose a developer wishes
to equip a scripting language (such as
video) with functions that check
whether their arguments satisfy specified predicates. Figure 4 shows the basic idea:
line 01 The module uses the racket
line 03 It exports a defined compile-time function, new-lambda, under the name lambda, which is overlined in the code to mark its origin as
line 05 Here, the module imports
tools from a library for creating robust
compile-time functions conveniently. 7
line 07 The comment says a function
on syntax trees follows.
line 08 While (define (f x) . . . )
introduces an ordinary function f of x,
(define-syntax (c stx) . . . ) creates the compile-time function c with a
single argument, stx.
line 09 As with many functional languages, Racket comes with pattern-matching constructs. This one uses
syntax-parse from the library mentioned earlier. Its first piece specifies
the to-be-matched tree (stx); the remainder specifies a series of pattern-responses clauses.
line 10 This pattern matches any
syntax tree with first token as new-lambda followed by a parameter specification and a body. The annotation
:id demands that the pattern variables
x and predicate match only identifi-
ers in the respective positions. Like-
wise, :expr allows only expressions to
match the body pattern variable.
line 11 A compile-time function syn-
thesizes new trees with syntax.
line 12 The generated syntax tree is a
lambda expression. Specifically, the
function generates an expression that
uses lambda. The underline in the
code marks its origin as the ambient
language, here racket.
other lines Wherever the syntax system encounters the pattern variables
x, predicate, and body, it inserts the
respective subtrees that match x, predicate, and body.
When another module uses “new-
lam” as its language, the compiler
that is, language development is a fric-
tion-free process in Racket.
In the world of shell scripts, the first-
line convention eventually opened the
door to a slew of alternatives to shells,
including Perl, Python, and Ruby. The
Racket world today reflects a similar
phenomenon, with language libraries
proliferating within its ecosystem:
racket/base, the Racket core lan-
guage; racket, the “batteries includ-
ed” variant; and typed/racket, a
typed variant. Some lesser-known ex-
amples are datalog and a web-serv-
er language. 27, 30 When precision is
needed, we use the lowercase name of
the language in typewriter font; other-
wise we use just “Racket.”
Figure 2 is an illustrative module. Its
first line—pronounced “hash lang rack-
et base”—says it is written in racket/
base. The module provides a single
function, walk-simplex. The accom-
panying line comments—introduced
with semicolons—informally state a
type definition and a function signature
in terms of this type definition; later, we
show how developers can use typed/
racket to replace such comments with
statically checked types, as in Figure 5.
To implement this function, the mod-
ule imports functionality from the con-
straints module outlined in Figure 3.
The last three lines of Figure 2 sketch
the definition of the walk-simplex
function, which refers to the maximiz-
er function imported from constraints.
The "constraints" module in Figure 3 expresses the implementation of its
only service in a domain-specific language because it deals with simplexes,
which are naturally expressed through a
system of inequalities. The module’s
simplex language inherits the line-com-ment syntax from racket/base but
uses infix syntax otherwise. As the comments state, the module exports a single
function, maximizer, which consumes
two optional keyword parameters. When
called as (maximizer #:x n), as in Figure
2, it produces the maximal y value of the
system of constraints. As in the lower half
of Figure 3, these constraints are specified with conventional syntax.
In support of this kind of programming, Racket’s modular syntax system
benefits from several key innovations.
A particularly illustrative one is the
ability to incrementally redefine the
meaning of existing language con-