Guide PDF
Guide PDF
Version 5.3.1
Matthew Flatt,
Robert Bruce Findler,
and PLT
November 6, 2012
This guide is intended for programmers who are new to Racket or new to some part of
Racket. It assumes programming experience, so if you are new to programming, consider
instead reading How to Design Programs. If you want an especially quick introduction to
Racket, start with Quick: An Introduction to Racket with Pictures.
Chapter 2 provides a brief introduction to Racket. From Chapter 3 on, this guide dives into
details—covering much of the Racket toolbox, but leaving precise details to The Racket
Reference and other reference manuals.
1
Contents
1 Welcome to Racket 14
2 Racket Essentials 18
2.2.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2.3 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2
2.4.2 Abbreviating quote with ' . . . . . . . . . . . . . . . . . . . . . . 39
3 Built-In Datatypes 42
3.1 Booleans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.2 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.3 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.6 Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.7 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.9 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.11 Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.1 Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3
4.4.2 Declaring Optional Arguments . . . . . . . . . . . . . . . . . . . . 68
4.7 Conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.8 Sequencing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4
4.10 Quoting: quote and ' . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6 Modules 113
5
6.4 Imports: require . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
7 Contracts 135
6
7.5 Contracts on Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
7
9.2 Matching Regexp Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 190
8
11.4 for/vector and for*/vector . . . . . . . . . . . . . . . . . . . . . . . 215
9
13.9.1 External Class Contracts . . . . . . . . . . . . . . . . . . . . . . . 239
16 Macros 268
10
16.1.2 Lexical Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
11
17.3.5 Source-Handling Configuration . . . . . . . . . . . . . . . . . . . 311
18 Performance 318
12
20 More Libraries 341
21.2.1 R5 RS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
21.2.2 R6 RS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Index 352
13
1 Welcome to Racket
• a programming language—a dialect of Lisp and a descendant of Scheme; See §21 “Dialects
of Racket and
• a family of programming languages—variants of Racket, and more; or Scheme” for more
information on
• a set of tools—for using a family of programming languages. other dialects of
Lisp and how they
relate to Racket.
Where there is no room for confusion, we use simply Racket.
Most likely, you’ll want to explore the Racket language using DrRacket, especially at the
beginning. If you prefer, you can also work with the command-line racket interpreter and
your favorite text editor; see also §22 “Command-Line Tools and Your Editor of Choice”.
The rest of this guide presents the language mostly independent of your choice of editor.
If you’re using DrRacket, you’ll need to choose the proper language, because DrRacket
accommodates many different variants of Racket, as well as other languages. Assuming that
you’ve never used DrRacket before, start it up, type the line
#lang racket
in DrRacket’s top text area, and then click the Run button that’s above the text area. Dr-
Racket then understands that you mean to work in the normal variant of Racket (as opposed
to the smaller racket/base or many other possibilities). §21.1 “More
Rackets” describes
If you’ve used DrRacket before with something other than a program that starts #lang, some of the other
possibilities.
DrRacket will remember the last language that you used, instead of inferring the language
from the #lang line. In that case, use the Language|Choose Language... menu item. In
the dialog that appears, select the first item, which tells DrRacket to use the language that is
declared in a source program via #lang. Put the #lang line above in the top text area, still.
14
1.1 Interacting with Racket
DrRacket’s bottom text area and the racket command-line program (when started with no
options) both act as a kind of calculator. You type a Racket expression, hit the Return key,
and the answer is printed. In the terminology of Racket, this kind of calculator is called a
read-eval-print loop or REPL.
> 5
5
A string is also an expression that evaluates to itself. A string is written with double quotes
at the start and end of the string:
Racket uses parentheses to wrap larger expressions—almost any kind of expression, other
than simple constants. For example, a function call is written: open parenthesis, function
name, argument expression, and closing parenthesis. The following expression calls the
built-in function substring with the arguments "the boy out of the country", 4,
and 7:
You can define your own functions that work like substring by using the define form,
like this:
Although you can evaluate the define form in the REPL, definitions are normally a part
of a program that you want to keep and use later. So, in DrRacket, you’d normally put the
definition in the top text area—called the definitions area—along with the #lang prefix:
15
#lang racket
If calling (extract "the boy") is part of the main action of your program, that would go
in the definitions area, too. But if it was just an example expression that you were using to
explore extract, then you’d more likely leave the definitions area as above, click Run, and
then evaluate (extract "the boy") in the REPL.
When using command-line racket instead of DrRacket, you’d save the above text in a file
using your favorite editor. If you save it as "extract.rkt", then after starting racket in
the same directory, you’d evaluate the following sequence: If you use xrepl,
you can use
> (enter! "extract.rkt") ,enter extract.rkt.
The enter! form both loads the code and switches the evaluation context to the inside of
the module, just like DrRacket’s Run button.
#lang racket
then it is a complete program that prints “cat” when run. You can run the program within
DrRacket or using enter! in racket, but if the program is saved in hsrc-filenamei, you can
also run it from a command line with
racket hsrc-filenamei
16
• From a command-line prompt, run raco exe hsrc-filenamei, where hsrc-filenamei
contains the program. See §3 “raco exe: Creating Stand-Alone Executables” for
more information.
• With Unix or Mac OS X, you can turn the program file into an executable script by
inserting the line See §19.2 “Scripts”
for more
#! /usr/bin/env racket information on
at the very beginning of the file. Also, change the file permissions to executable using script files.
chmod +x hfilenamei on the command line.
The script works as long as racket is in the user’s executable search path. Alternately,
use a full path to racket after #! (with a space between #! and the path), in which
case the user’s executable search path does not matter.
If you already know something about Racket or Lisp, you might be tempted to put just
That will work, because racket is willing to imitate a traditional Lisp environment, but we
strongly recommend against using load or writing programs outside of a module.
Writing definitions outside of a module leads to bad error messages, bad performance, and
awkward scripting to combine and run programs. The problems are not specific to racket;
they’re fundamental limitations of the traditional top-level environment, which Scheme and
Lisp implementations have historically fought with ad hoc command-line flags, compiler
directives, and build tools. The module system is designed to avoid these problems, so start
with #lang, and you’ll be happier with Racket in the long run.
17
2 Racket Essentials
This chapter provides a quick introduction to Racket as background for the rest of the guide.
Readers with some Racket experience can safely skip to §3 “Built-In Datatypes”.
Racket values include numbers, booleans, strings, and byte strings. In DrRacket and doc-
umentation examples (when you read the documentation in color), value expressions are
shown in green.
Numbers are written in the usual way, including fractions and imaginary numbers: §3.2 “Numbers”
(later in this guide)
1 3.14 explains more about
1/2 6.02e+23 numbers.
1+2i 9999999999999999999999
Booleans are #t for true and #f for false. In conditionals, however, all non-#f values are
treated as true. §3.1 “Booleans”
(later in this guide)
Strings are written between doublequotes. Within a string, backslash is an escaping char- explains more about
booleans.
acter; for example, a backslash followed by a doublequote includes a literal doublequote in
the string. Except for an unescaped doublequote or backslash, any Unicode character can
appear in a string constant. §3.4 “Strings
(Unicode)” (later in
"Hello, world!" this guide) explains
"Benjamin \"Bugsy\" Siegel" more about strings.
"λx:(µα.α→α).xx"
When a constant is evaluated in the REPL, it typically prints the same as its input syntax.
In some cases, the printed form is a normalized version of the input syntax. In documen-
tation and in DrRacket’s REPL, results are printed in blue instead of green to highlight the
difference between an input expression and a printed result.
Examples:
> 1.0000
1.0
> "Bugs \u0022Figaro\u0022 Bunny"
"Bugs \"Figaro\" Bunny"
18
#lang hlangnamei htopformi*
where a htopformi is either a hdefinitioni or an hexpri. The REPL also evaluates htopformis.
In syntax specifications, text with a gray background, such as #lang, represents literal text.
Whitespace must appear between such literals and nonterminals like hidi, except that whites-
pace is not required before or after (, ), [, or ]. A comment, which starts with ; and runs
until the end of the line, is treated the same as whitespace. §1.3.8 “Reading
Comments” in The
Following the usual conventions, * in a grammar means zero or more repetitions of the Racket Reference
provides more on
preceding element, + means one or more repetitions of the preceding element, and {} groups different forms of
a sequence as an element for repetition. comments.
2.2.1 Definitions
binds the first hidi to a function (also called a procedure) that takes arguments as named by
the remaining hidis. In the function case, the hexpris are the body of the function. When the
function is called, it returns the result of the last hexpri.
Examples:
(define pie 3) ; defines pie to be 3
> pie
3
> (piece "key lime")
"key"
Under the hood, a function definition is really the same as a non-function definition, and a
function name does not have to be used in a function call. A function is just another kind of
value, though the printed form is necessarily less complete than the printed form of a number
or string.
Examples:
19
> piece
#<procedure:piece>
> substring
#<procedure:substring>
A function definition can include multiple expressions for the function’s body. In that case,
only the value of the last expression is returned when the function is called. The other
expressions are evaluated only for some side-effect, such as printing.
Examples:
Racket programmers prefer to avoid side-effects, so a definition usually has just one expres-
sion in its body. It’s important, though, to understand that multiple expressions are allowed
in a definition body, because it explains why the following nobake function fails to include
its argument in its result:
Line breaks and indentation are not significant for parsing Racket programs, but most Racket
programmers use a standard set of conventions to make code more readable. For example,
the body of a definition is typically indented under the first line of the definition. Identifiers
are written immediately after an open parenthesis with no extra space, and closing parenthe-
ses never go on their own line.
DrRacket automatically indents according to the standard style when you type En-
ter in a program or REPL expression. For example, if you hit Enter after typing
20
(define (greet name), then DrRacket automatically inserts two spaces for the next line.
If you change a region of code, you can select it in DrRacket and hit Tab, and DrRacket will
re-indent the code (without inserting any line breaks). Editors like Emacs offer a Racket or
Scheme mode with similar indentation support.
Re-indenting not only makes the code easier to read, it gives you extra feedback that your
parentheses match in the way that you intended. For example, if you leave out a closing
parenthesis after the last argument to a function, automatic indentation starts the next line
under the first argument, instead of under the define keyword:
(define (halfbake flavor
(string-append flavor " creme brulee")))
In this case, indentation helps highlight the mistake. In other cases, where the indentation
may be normal while an open parenthesis has no matching close parenthesis, both racket
and DrRacket use the source’s indentation to suggest where a parenthesis might be missing.
2.2.3 Identifiers
Racket’s syntax for identifiers is especially liberal. Excluding the special characters §4.2 “Identifiers
and Binding” (later
()[]{}",'`;#|\ in this guide)
explains more about
identifiers.
and except for the sequences of characters that make number constants, almost any sequence
of non-whitespace characters forms an hidi. For example substring is an identifier. Also,
string-append and a+b are identifiers, as opposed to arithmetic expressions. Here are
several more examples:
+
Hfuhruhurr
integer?
pass/fail
john-jacob-jingleheimer-schmidt
a-b-c+1-2-3
We have already seen many function calls, which are called procedure applications in more
traditional terminology. The syntax of a function call is §4.3 “Function
Calls (Procedure
( hidi hexpri* ) Applications)”
(later in this guide)
explains more about
where the number of hexpris determines the number of arguments supplied to the function function calls.
named by hidi.
21
The racket language pre-defines many function identifiers, such as substring and
string-append. More examples are below.
In example Racket code throughout the documentation, uses of pre-defined names are hy-
perlinked to the reference manual. So, you can click on an identifier to get full details about
its use.
22
§4.7 “Conditionals”
(later in this guide)
The first hexpri is always evaluated. If it produces a non-#f value, then the second hexpri is explains more about
evaluated for the result of the whole if expression, otherwise the third hexpri is evaluated conditionals.
for the result.
Example:
> (if (> 2 3)
"bigger"
"smaller")
"smaller"
(define (reply s)
(if (equal? "hello" (substring s 0 5))
"hi!"
"huh?"))
Complex conditionals can be formed by nesting if expressions. For example, you could
make the reply function work when given non-strings:
(define (reply s)
(if (string? s)
(if (equal? "hello" (substring s 0 5))
"hi!"
"huh?")
"huh?"))
but these kinds of nested ifs are difficult to read. Racket provides more readable shortcuts
through the and and or forms, which work with any number of expressions: §4.7.2 “Combining
Tests: and and or”
( and hexpri* ) (later in this guide)
( or hexpri* ) explains more about
and and or.
23
The and form short-circuits: it stops and returns #f when an expression produces #f, other-
wise it keeps going. The or form similarly short-circuits when it encounters a true result.
Examples:
(define (reply s)
(if (and (string? s)
(>= (string-length s) 5)
(equal? "hello" (substring s 0 5)))
"hi!"
"huh?"))
Another common pattern of nested ifs involves a sequence of tests, each with its own result:
(define (reply-more s)
(if (equal? "hello" (substring s 0 5))
"hi!"
(if (equal? "goodbye" (substring s 0 7))
"bye!"
(if (equal? "?" (substring s (- (string-length s) 1)))
"I don't know"
"huh?"))))
The shorthand for a sequence of tests is the cond form: §4.7.3 “Chaining
Tests: cond” (later
( cond {[ hexpri hexpri* ]}* ) in this guide)
explains more about
cond.
A cond form contains a sequence of clauses between square brackets. In each clause, the
first hexpri is a test expression. If it produces true, then the clause’s remaining hexpris are
evaluated, and the last one in the clause provides the answer for the entire cond expression;
the rest of the clauses are ignored. If the test hexpri produces #f, then the clause’s remaining
hexpris are ignored, and evaluation continues with the next clause. The last clause can use
else as a synonym for a #t test expression.
Using cond, the reply-more function can be more clearly written as follows:
(define (reply-more s)
(cond
[(equal? "hello" (substring s 0 5))
"hi!"]
[(equal? "goodbye" (substring s 0 7))
24
"bye!"]
[(equal? "?" (substring s (- (string-length s) 1)))
"I don't know"]
[else "huh?"]))
The use of square brackets for cond clauses is a convention. In Racket, parentheses and
square brackets are actually interchangeable, as long as ( is matched with ) and [ is matched
with ]. Using square brackets in a few key places makes Racket code even more readable.
In our earlier grammar of function calls, we oversimplified. The actual syntax of a function
call allows an arbitrary expression for the function, instead of just an hidi: §4.3 “Function
Calls (Procedure
( hexpri hexpri* ) Applications)”
(later in this guide)
explains more about
function calls.
The first hexpri is often an hidi, such as string-append or +, but it can be anything that
evaluates to a function. For example, it can be a conditional expression:
(define (double v)
((if (string? v) string-append +) v v))
Syntactically, the first expression in a function call could even be a number—but that leads
to an error, since a number is not a function.
> (1 2 3 4)
application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
25
arguments...:
2
3
4
When you accidentally omit a function name or when you use parentheses around an expres-
sion, you’ll most often get an “expected a procedure” error like this one.
Programming in Racket would be tedious if you had to name all of your numbers. Instead
of writing (+ 1 2), you’d have to write §4.4 “Functions
(Procedures):
> (define a 1) lambda” (later in
this guide) explains
more about
> (define b 2) lambda.
> (+ a b)
3
It turns out that having to name all your functions can be tedious, too. For example, you
might have a function twice that takes a function and an argument. Using twice is conve-
nient if you already have a name for the function, such as sqrt:
(define (twice f v)
(f (f v)))
If you want to call a function that is not yet defined, you could define it, and then pass it to
twice:
(define (louder s)
(string-append s "!"))
But if the call to twice is the only place where louder is used, it’s a shame to have to
write a whole definition. In Racket, you can use a lambda expression to produce a function
directly. The lambda form is followed by identifiers for the function’s arguments, and then
the function’s body expressions:
26
( lambda ( hidi* ) hexpri+ )
Racket is a lexically scoped language, which means that s2 in the function returned by
make-add-suffix always refers to the argument for the call that created the function. In
other words, the lambda-generated function “remembers” the right s2:
> (define louder (make-add-suffix "!"))
We have so far referred to definitions of the form (define hidi hexpri) as “non-function
definitions.” This characterization is misleading, because the hexpri could be a lambda
form, in which case the definition is equivalent to using the “function” definition form. For
example, the following two definitions of louder are equivalent:
27
(define (louder s)
(string-append s "!"))
(define louder
(lambda (s)
(string-append s "!")))
> louder
#<procedure:louder>
Note that the expression for louder in the second case is an “anonymous” function written
with lambda, but, if possible, the compiler infers a name, anyway, to make printing and error
reporting as informative as possible.
It’s time to retract another simplification in our grammar of Racket. In the body of a function,
definitions can appear before the body expressions: §4.5.4 “Internal
Definitions” (later
( define ( hidi hidi* ) hdefinitioni* hexpri+ ) in this guide)
explains more about
( lambda ( hidi* ) hdefinitioni* hexpri+ ) local (internal)
definitions.
Definitions at the start of a function body are local to the function body.
Examples:
(define (converse s)
(define (starts? s2) ; local to converse
(define len2 (string-length s2)) ; local to starts?
(and (>= (string-length s) len2)
(equal? s2 (substring s 0 len2))))
(cond
[(starts? "hello") "hi!"]
[(starts? "goodbye") "bye!"]
[else "huh?"]))
28
Another way to create local bindings is the let form. An advantage of let is that it can
be used in any expression position. Also, let binds many identifiers at once, instead of
requiring a separate define for each identifier. §4.5.4 “Internal
Definitions” (later
( let ( {[ hidi hexpri ]}* ) hexpri+ ) in this guide)
explains more about
let and let*.
Each binding clause is an hidi and a hexpri surrounded by square brackets, and the expres-
sions after the clauses are the body of the let. In each clause, the hidi is bound to the result
of the hexpri for use in the body.
> (let ([x (random 4)]
[o (random 4)])
(cond
[(> x o) "X wins"]
[(> o x) "O wins"]
[else "cat's game"]))
"cat's game"
The bindings of a let form are available only in the body of the let, so the binding clauses
cannot refer to each other. The let* form, in contrast, allows later clauses to use earlier
bindings:
> (let* ([x (random 4)]
[o (random 4)]
[diff (number->string (abs (- x o)))])
(cond
[(> x o) (string-append "X wins by " diff)]
[(> o x) (string-append "O wins by " diff)]
[else "cat's game"]))
"O wins by 2"
Racket is a dialect of the language Lisp, whose name originally stood for “LISt Processor.”
The built-in list datatype remains a prominent feature of the language.
The list function takes any number of values and returns a list containing the values:
> (list "red" "green" "blue")
'("red" "green" "blue")
> (list 1 2 3 4 5)
'(1 2 3 4 5)
A list usually prints
with ', but the
As you can see, a list result prints in the REPL as a quote ' and then a pair of parentheses printed form of a
list depends on its
wrapped around the printed form of the list elements. There’s an opportunity for confusion content. See §3.8
“Pairs and Lists” for
more information.
29
here, because parentheses are used for both expressions, such as (list "red" "green"
"blue"), and printed results, such as '("red" "green" "blue"). In addition to the
quote, parentheses for results are printed in blue in the documentation and in DrRacket,
whereas parentheses for expressions are brown.
In addition to simple operations like append, Racket includes functions that iterate over the
elements of a list. These iteration functions play a role similar to for in Java, Racket, and
other languages. The body of a Racket iteration is packaged into a function to be applied to
each element, so the lambda form becomes particularly handy in combination with iteration
functions.
Different list-iteration functions combine iteration results in different ways. The map func-
tion uses the per-element results to create a new list:
The andmap and ormap functions combine the results by anding or oring:
30
> (ormap number? (list "a" "b" 6))
#t
The filter function keeps elements for which the body result is true, and discards elements
for which it is #f:
> (filter string? (list "a" "b" 6))
'("a" "b")
> (filter positive? (list 1 -2 6 7 0))
'(1 6 7)
The map, andmap, ormap, and filter functions can all handle multiple lists, instead of just
a single list. The lists must all have the same length, and the given function must accept one
argument for each list:
> (map (lambda (s n) (substring s 0 n))
(list "peanuts" "popcorn" "crackerjack")
(list 6 3 7))
'("peanut" "pop" "cracker")
The foldl function generalizes some iteration functions. It uses the per-element function to
both process an element and combine it with the “current” value, so the per-element function
takes an extra first argument. Also, a starting “current” value must be provided before the
lists:
> (foldl (lambda (elem v)
(+ v (* elem elem)))
0
'(1 2 3))
14
Despite its generality, foldl is not as popular as the other functions. One reason is that map,
ormap, andmap, and filter cover the most common kinds of list loops.
Racket provides a general list comprehension form for/list, which builds a list by iterating
through sequences. List comprehensions and related iteration forms are described in §11
“Iterations and Comprehensions”.
Although map and other iteration functions are predefined, they are not primitive in any
interesting sense. You can write equivalent iterations using a handful of list primitives.
Since a Racket list is a linked list, the two core operations on a non-empty list are
31
• first: get the first thing in the list; and
• rest: get the rest of the list.
Examples:
To create a new node for a linked list—that is, to add to the front of the list—use the cons
function, which is short for “construct.” To get an empty list to start with, use the empty
constant:
> empty
'()
> (cons "head" empty)
'("head")
> (cons "dead" (cons "head" empty))
'("dead" "head")
To process a list, you need to be able to distinguish empty lists from non-empty lists, because
first and rest work only on non-empty lists. The empty? function detects empty lists,
and cons? detects non-empty lists:
With these pieces, you can write your own versions of the length function, map function,
and more.
Examples:
32
> (my-length empty)
0
> (my-length (list "a" "b" "c"))
3
If the derivation of the above definitions is mysterious to you, consider reading How to
Design Programs. If you are merely suspicious of the use of recursive calls instead of a
looping construct, then read on.
Both the my-length and my-map functions run in O(n) time for a list of length n. This is
easy to see by imagining how (my-length (list "a" "b" "c")) must evaluate:
For a list with n elements, evaluation will stack up n (+ 1 ...) additions, and then finally
add them up when the list is exhausted.
You can avoid piling up additions by adding along the way. To accumulate a length this way,
we need a function that takes both a list and the length of the list seen so far; the code below
uses a local function iter that accumulates the length in an argument len:
33
[(empty? lst) len]
[else (iter (rest lst) (+ len 1))]))
; body of my-length calls iter:
(iter lst 0))
The revised my-length runs in constant space, just as the evaluation steps above suggest.
That is, when the result of a function call, like (iter (list "b" "c") 1), is exactly the
result of some other function call, like (iter (list "c") 2), then the first one doesn’t
have to wait around for the second one, because that takes up space for no good reason.
This evaluation behavior is sometimes called tail-call optimization, but it’s not merely an
“optimization” in Racket; it’s a guarantee about the way the code will run. More precisely, an
expression in tail position with respect to another expression does not take extra computation
space over the other expression.
In the case of my-map, O(n) space complexity is reasonable, since it has to generate a result
of size O(n). Nevertheless, you can reduce the constant factor by accumulating the result
list. The only catch is that the accumulated list will be backwards, so you’ll have to reverse
it at the very end: Attempting to
reduce a constant
(define (my-map f lst) factor like this is
(define (iter lst backward-result) usually not
worthwhile, as
(cond discussed below.
[(empty? lst) (reverse backward-result)]
[else (iter (rest lst)
(cons (f (first lst))
backward-result))]))
(iter lst empty))
then the for/list form in the function is expanded to essentially the same code as the iter
local definition and use. The difference is merely syntactic convenience.
34
2.3.4 Recursion versus Iteration
The my-length and my-map examples demonstrate that iteration is just a special case of
recursion. In many languages, it’s important to try to fit as many computations as possible
into iteration form. Otherwise, performance will be bad, and moderately large inputs can
lead to stack overflow. Similarly, in Racket, it is sometimes important to make sure that tail
recursion is used to avoid O(n) space consumption when the computation is easily performed
in constant space.
At the same time, recursion does not lead to particularly bad performance in Racket, and
there is no such thing as stack overflow; you can run out of memory if a computation involves
too much context, but exhausting memory typically requires orders of magnitude deeper
recursion than would trigger a stack overflow in other languages. These considerations,
combined with the fact that tail-recursive programs automatically run the same as a loop,
lead Racket programmers to embrace recursive forms rather than avoid them.
Suppose, for example, that you want to remove consecutive duplicates from a list. While
such a function can be written as a loop that remembers the previous element for each itera-
tion, a Racket programmer would more likely just write the following:
(define (remove-dups l)
(cond
[(empty? l) empty]
[(empty? (rest l)) l]
[else
(let ([i (first l)])
(if (equal? i (first (rest l)))
(remove-dups (rest l))
(cons i (remove-dups (rest l)))))]))
In general, this function consumes O(n) space for an input list of length n, but that’s fine,
since it produces an O(n) result. If the input list happens to be mostly consecutive duplicates,
then the resulting list can be much smaller than O(n)—and remove-dups will also use much
less than O(n) space! The reason is that when the function discards duplicates, it returns the
result of a remove-dups call directly, so the tail-call “optimization” kicks in:
35
= (list "a" "b")
The cons function actually accepts any two values, not just a list for the second argument.
When the second argument is not empty and not itself produced by cons, the result prints in
a special way. The two values joined with cons are printed between parentheses, but with a
dot (i.e., a period surrounded by whitespace) in between:
> (cons 1 2)
'(1 . 2)
> (cons "banana" "split")
'("banana" . "split")
Thus, a value produced by cons is not always a list. In general, the result of cons is a pair.
The more traditional name for the cons? function is pair?, and we’ll use the traditional
name from now on.
The name rest also makes less sense for non-list pairs; the more traditional names for
first and rest are car and cdr, respectively. (Granted, the traditional names are also
nonsense. Just remember that “a” comes before “d,” and cdr is pronounced “could-er.”)
Examples:
Racket’s pair datatype and its relation to lists is essentially a historical curiosity, along with
the dot notation for printing and the funny names car and cdr. Pairs are deeply wired into
to the culture, specification, and implementation of Racket, however, so they survive in the
language.
You are perhaps most likely to encounter a non-list pair when making a mistake, such as
accidentally reversing the arguments to cons:
36
> (cons 1 (list 2 3))
'(1 2 3)
Non-list pairs are used intentionally, sometimes. For example, the make-hash function takes
a list of pairs, where the car of each pair is a key and the cdr is an arbitrary value.
The only thing more confusing to new Racketeers than non-list pairs is the printing conven-
tion for pairs where the second element is a pair, but is not a list:
In general, the rule for printing a pair is as follows: use the dot notation always, but if the dot
is immediately followed by an open parenthesis, then remove the dot, the open parenthesis,
and the matching close parenthesis. Thus, '(0 . (1 . 2)) becomes '(0 1 . 2), and
'(1 . (2 . (3 . ()))) becomes '(1 2 3).
A list prints with a quote mark before it, but if an element of a list is itself a list, then no
quote mark is printed for the inner list:
For nested lists, especially, the quote form lets you write a list as an expression in essentially
the same way that the list prints:
The quote form works with the dot notation, too, whether the quoted form is normalized by
the dot-parenthesis elimination rule or not:
37
Naturally, lists of any kind can be nested:
> (list (list 1 2 3) 5 (list "a" "b" "c"))
'((1 2 3) 5 ("a" "b" "c"))
> (quote ((1 2 3) 5 ("a" "b" "c")))
'((1 2 3) 5 ("a" "b" "c"))
If you wrap an identifier with quote, then you get output that looks like an identifier, but
with a ' prefix:
> (quote jane-doe)
'jane-doe
A value that prints like a quoted identifier is a symbol. In the same way that parenthesized
output should not be confused with expressions, a printed symbol should not be confused
with an identifier. In particular, the symbol (quote map) has nothing to do with the map
identifier or the predefined function that is bound to map, except that the symbol and the
identifier happen to be made up of the same letters.
Indeed, the intrinsic value of a symbol is nothing more than its character content. In this
sense, symbols and strings are almost the same thing, and the main difference is how they
print. The functions symbol->string and string->symbol convert between them.
Examples:
> map
#<procedure:map>
> (quote map)
'map
> (symbol? (quote map))
#t
> (symbol? map)
#f
> (procedure? map)
#t
> (string->symbol "map")
'map
> (symbol->string (quote map))
"map"
In the same way that quote for a list automatically applies itself to nested lists, quote on a
parenthesized sequence of identifiers automatically applies itself to the identifiers to create
a list of symbols:
> (car (quote (road map)))
'road
> (symbol? (car (quote (road map))))
#t
38
When a symbol is inside a list that is printed with ', the ' on the symbol is omitted, since '
is doing the job already:
The quote form has no effect on a literal expression such as a number or string:
As you may have guessed, you can abbreviate a use of quote by just putting ' in front of a
form to quote:
> '(1 2 3)
'(1 2 3)
> 'road
'road
> '((1 2 3) road ("a" "b" "c"))
'((1 2 3) road ("a" "b" "c"))
In the documentation, ' within an expression is printed in green along with the form after
it, since the combination is an expression that is a constant. In DrRacket, only the ' is
colored green. DrRacket is more precisely correct, because the meaning of quote can vary
depending on the context of an expression. In the documentation, however, we routinely
assume that standard bindings are in scope, and so we paint quoted forms in green for extra
clarity.
A ' expands to a quote form in quite a literal way. You can see this if you put a ' in front
of a form that has a ':
The ' abbreviation works in output as well as input. The REPL’s printer recognizes the
symbol 'quote as the first element of a two-element list when printing output, in which
case it uses ' to print the output:
39
> (quote (quote road))
''road
> '(quote road)
''road
> ''road
''road
Now that you know the truth about pairs and lists, and now that you’ve seen quote, you’re
ready to understand the main way in which we have been simplifying Racket’s true syntax.
The syntax of Racket is not defined directly in terms of character streams. Instead, the syntax
is determined by two layers:
• a reader layer, which turns a sequence of characters into lists, symbols, and other
constants; and
• an expander layer, which processes the lists, symbols, and other constants to parse
them as an expression.
The rules for printing and reading go together. For example, a list is printed with parentheses,
and reading a pair of parentheses produces a list. Similarly, a non-list pair is printed with the
dot notation, and a dot on input effectively runs the dot-notation rules in reverse to obtain a
pair.
One consequence of the read layer for expressions is that you can use the dot notation in
expressions that are not quoted forms:
> (+ 1 . (2))
3
This works because (+ 1 . (2)) is just another way of writing (+ 1 2). It is practically
never a good idea to write application expressions using this dot notation; it’s just a conse-
quence of the way Racket’s syntax is defined.
Normally, . is allowed by the reader only with a parenthesized sequence, and only before the
last element of the sequence. However, a pair of .s can also appear around a single element
in a parenthesized sequence, as long as the element is not first or last. Such a pair triggers a
reader conversion that moves the element between .s to the front of the list. The conversion
enables a kind of general infix notation:
> (1 . < . 2)
#t
40
> '(1 . < . 2)
'(< 1 2)
This two-dot convention is non-traditional, and it has essentially nothing to do with the dot
notation for non-list pairs. Racket programmers use the infix convention sparingly—mostly
for asymmetric binary operators such as < and is-a?.
41
3 Built-In Datatypes
The previous chapter introduced some of Racket’s built-in datatypes: numbers, booleans,
strings, lists, and procedures. This section provides a more complete coverage of the built-in
datatypes for simple forms of data.
3.1 Booleans
Racket has two distinguished constants to represent boolean values: #t for true and #f for
false. Uppercase #T and #F are parsed as the same values, but the lowercase forms are
preferred.
The boolean? procedure recognizes the two boolean constants. In the result of a test ex-
pression for if, cond, and, or, etc., however, any value other than #f counts as true.
Examples:
> (= 2 (+ 1 1))
#t
> (boolean? #t)
#t
> (boolean? #f)
#t
> (boolean? "no")
#f
> (if "no" 1 0)
1
3.2 Numbers
42
– an IEEE floating-point representation of a number, such as 2.0 or 3.14e+87,
where the IEEE infinities and not-a-number are written +inf.0, -inf.0, and
+nan.0 (or -nan.0); or
– a complex number with real and imaginary parts that are IEEE floating-point
representations, such as 2.0+3.0i or -inf.0+nan.0i; as a special case, an in-
exact complex number can have an exact zero real part with an inexact imaginary
part.
Inexact numbers print with a decimal point or exponent specifier, and exact numbers print as
integers and fractions. The same conventions apply for reading number constants, but #e or
#i can prefix a number to force its parsing as an exact or inexact number. The prefixes #b,
#o, and #x specify binary, octal, and hexadecimal interpretation of digits. §1.3.3 “Reading
Numbers” in The
Examples: Racket Reference
documents the fine
points of the syntax
> 0.5 of numbers.
0.5
> #e0.5
1/2
> #x03BB
955
Computations that involve an inexact number produce inexact results, so that inexactness
acts as a kind of taint on numbers. Beware, however, that Racket offers no “inexact
booleans,” so computations that branch on the comparison of inexact numbers can nev-
ertheless produce exact results. The procedures exact->inexact and inexact->exact
convert between the two types of numbers.
Examples:
> (/ 1 2)
1/2
> (/ 1 2.0)
0.5
> (if (= 3.0 2.999) 1 2)
2
> (inexact->exact 0.1)
3602879701896397/36028797018963968
Inexact results are also produced by procedures such as sqrt, log, and sin when an exact
result would require representing real numbers that are not rational. Racket can represent
only rational numbers and complex numbers with rational parts.
Examples:
43
> (sin 1/2) ; not rational...
0.479425538604203
In terms of performance, computations with small integers are typically the fastest, where
“small” means that the number fits into one bit less than the machine’s word-sized represen-
tation for signed numbers. Computation with very large exact integers or with non-integer
exact numbers can be much more expensive than computation with inexact numbers.
(define (sigma f a b)
(if (= a b)
0
(+ (f a) (sigma f (+ a 1) b))))
The number categories integer, rational, real (always rational), and complex are defined in
the usual way, and are recognized by the procedures integer?, rational?, real?, and
complex?, in addition to the generic number?. A few mathematical procedures accept only
real numbers, but most implement standard extensions to complex numbers.
Examples:
> (integer? 5)
#t
> (complex? 5)
#t
> (integer? 5.0)
#t
> (integer? 1+2i)
#f
> (complex? 1+2i)
#t
> (complex? 1.0+2.0i)
#t
> (abs -5)
5
> (abs -5+2i)
abs: contract violation
expected: real?
given: -5+2i
> (sin -5+2i)
3.6076607742131563+1.0288031496599335i
44
The = procedure compares numbers for numerical equality. If it is given both inexact and
exact numbers to compare, it essentially converts the inexact numbers to exact before com-
paring. The eqv? (and therefore equal?) procedure, in contrast, compares numbers consid-
ering both exactness and numerical equality.
Examples:
> (= 1 1.0)
#t
> (eqv? 1 1.0)
#f
Beware of comparisons involving inexact numbers, which by their nature can have surprising
behavior. Even apparently simple inexact numbers may not mean what you think they mean;
for example, while a base-2 IEEE floating-point number can represent 1/2 exactly, it can
only approximate 1/10:
Examples:
Although each Racket character corresponds to an integer, the character datatype is sepa-
rate from numbers. The char->integer and integer->char procedures convert between
scalar-value numbers and the corresponding character.
The display procedure directly writes a character to the current output port (see §8 “Input
and Output”), in contrast to the character-constant syntax used to print a character result.
Examples:
> #\A
#\A
> (display #\A)
A
Examples:
The char=? procedure compares two or more characters, and char-ci=? compares char-
acters ignoring case. The eqv? and equal? procedures behave the same as char=? on
characters; use char=? when you want to more specifically declare that the values being
compared are characters.
Examples:
46
> (char=? #\a #\A)
#f
> (char-ci=? #\a #\A)
#t
> (eqv? #\a #\A)
#f §3.5 “Characters”
in The Racket
Reference provides
more on characters
3.4 Strings (Unicode) and character
procedures.
Examples:
> "Apple"
"Apple"
> "\u03BB"
"λ "
> (display "Apple")
Apple
A string can be mutable or immutable; strings written directly as expressions are immutable,
but most other strings are mutable. The make-string procedure creates a mutable string
given a length and optional fill character. The string-ref procedure accesses a character
from a string (with 0-based indexing); the string-set! procedure changes a character in a
mutable string.
47
Examples:
> s
"....."
> (string-set! s 2 #\λ)
> s
"..λ.."
String ordering and case operations are generally locale-independent; that is, they work
the same for all users. A few locale-dependent operations are provided that allow the way
that strings are case-folded and sorted to depend on the end-user’s locale. If you’re sorting
strings, for example, use string<? or string-ci<? if the sort result should be consistent
across machines and users, but use string-locale<? or string-locale-ci<? if the sort
is purely to order strings for an end user.
Examples:
For working with plain ASCII, working with raw bytes, or encoding/decoding Unicode
strings as bytes, use byte strings. §3.3 “Strings” in
The Racket
Reference provides
more on strings and
3.5 Bytes and Byte Strings string procedures.
A byte is an exact integer between 0 and 255, inclusive. The byte? predicate recognizes
numbers that represent bytes.
Examples:
> (byte? 0)
#t
> (byte? 256)
#f
48
A byte string is similar to a string—see §3.4 “Strings (Unicode)”—but its content is a se-
quence of bytes instead of characters. Byte strings can be used in applications that process
pure ASCII instead of Unicode text. The printed form of a byte string supports such uses
in particular, because a byte string prints like the ASCII decoding of the byte string, but
prefixed with a #. Unprintable ASCII characters or non-ASCII bytes in the byte string are
written with octal notation. §1.3.6 “Reading
Strings” in The
Examples: Racket Reference
documents the fine
points of the syntax
> #"Apple" of byte strings.
#"Apple"
> (bytes-ref #"Apple" 0)
65
> (make-bytes 3 65)
#"AAA"
> (define b (make-bytes 2 0))
> b
#"\0\0"
> (bytes-set! b 0 1)
> b
#"\1\377"
The display form of a byte string writes its raw bytes to the current output port (see §8
“Input and Output”). Technically, display of a normal (i.e,. character) string prints the
UTF-8 encoding of the string to the current output port, since output is ultimately defined in
terms of bytes; display of a byte string, however, writes the raw bytes with no encoding.
Along the same lines, when this documentation shows output, it technically shows the UTF-
8-decoded form of the output.
Examples:
For explicitly converting between strings and byte strings, Racket supports three kinds of
encodings directly: UTF-8, Latin-1, and the current locale’s encoding. General facilities
49
for byte-to-byte conversions (especially to and from UTF-8) fill the gap to support arbitrary
string encodings.
Examples:
Examples:
> 'a
'a
> (symbol? 'a)
#t
For any sequence of characters, exactly one corresponding symbol is interned; calling the
string->symbol procedure, or reading a syntactic identifier, produces an interned symbol.
Since interned symbols can be cheaply compared with eq? (and thus eqv? or equal?), they
serve as a convenient values to use for tags and enumerations.
Symbols are case-sensitive. By using a #ci prefix or in other ways, the reader can be made to
case-fold character sequences to arrive at a symbol, but the reader preserves case by default.
Examples:
50
> (eq? 'a (string->symbol "a"))
#t
> (eq? 'a 'b)
#f
> (eq? 'a 'A)
#f
> #ci'A
'a
Any string (i.e., any character sequence) can be supplied to string->symbol to obtain the
corresponding symbol. For reader input, any character can appear directly in an identifier,
except for whitespace and the following special characters:
()[]{}",'`;#|\
Actually, # is disallowed only at the beginning of a symbol, and then only if not followed by
%; otherwise, # is allowed, too. Also, . by itself is not a symbol.
Examples:
> (string->symbol "one, two")
'|one, two|
> (string->symbol "6")
'|6| §1.3.2 “Reading
Symbols” in The
The write function prints a symbol without a ' prefix. The display form of a symbol is Racket Reference
documents the fine
the same as the corresponding string. points of the syntax
of symbols.
Examples:
> (write 'Apple)
Apple
51
bol. Uninterned symbols are useful as fresh tags that cannot be confused with any other
value.
Examples:
> s
'g42
> (eq? s 'g42)
#f
> (eq? 'a (string->uninterned-symbol "a"))
#f §3.6 “Symbols” in
The Racket
Reference provides
more on symbols.
3.7 Keywords
A keyword value is similar to a symbol (see §3.6 “Symbols”), but its printed form is prefixed
with #:. §1.3.14 “Reading
Keywords” in The
Examples: Racket Reference
documents the fine
points of the syntax
> (string->keyword "apple") of keywords.
'#:apple
> '#:apple
'#:apple
> (eq? '#:apple (string->keyword "apple"))
#t
More precisely, a keyword is analogous to an identifier; in the same way that an identifier
can be quoted to produce a symbol, a keyword can be quoted to produce a value. The
same term “keyword” is used in both cases, but we sometimes use keyword value to refer
more specifically to the result of a quote-keyword expression or of string->keyword. An
unquoted keyword is not an expression, just as an unquoted identifier does not produce a
symbol:
Examples:
> not-a-symbol-expression
not-a-symbol-expression: undefined;
cannot reference undefined identifier
> #:not-a-keyword-expression
eval:2:0: #%datum: keyword used as an expression
in: #:not-a-keyword-expression
Despite their similarities, keywords are used in a different way than identifiers or symbols.
Keywords are intended for use (unquoted) as special markers in argument lists and in certain
52
syntactic forms. For run-time flags and enumerations, use symbols instead of keywords. The
example below illustrates the distinct roles of keywords and symbols.
Examples:
A pair joins two arbitrary values. The cons procedure constructs pairs, and the car and
cdr procedures extract the first and second elements of the pair, respectively. The pair?
predicate recognizes pairs.
Some pairs print by wrapping parentheses around the printed forms of the two pair elements,
putting a ' at the beginning and a . between the elements.
Examples:
> (cons 1 2)
'(1 . 2)
> (cons (cons 1 2) 3)
'((1 . 2) . 3)
> (car (cons 1 2))
1
> (cdr (cons 1 2))
2
> (pair? (cons 1 2))
#t
A list is a combination of pairs that creates a linked list. More precisely, a list is either the
empty list null, or it is a pair whose first element is a list element and whose second element
is a list. The list? predicate recognizes lists. The null? predicate recognizes the empty
list.
A list normally prints as a ' followed by a pair of parentheses wrapped around the list
elements.
Examples:
53
> null
'()
> (cons 0 (cons 1 (cons 2 null)))
'(0 1 2)
> (list? null)
#t
> (list? (cons 1 (cons 2 null)))
#t
> (list? (cons 1 2))
#f
A list or pair prints using list or cons when one of its elements cannot be written as
a quoted value. For example, a value constructed with srcloc cannot be written using
quote, and it prints using srcloc:
> (srcloc "file.rkt" 1 0 1 (+ 4 4))
(srcloc "file.rkt" 1 0 1 8)
> (list 'here (srcloc "file.rkt" 1 0 1 8) 'there)
(list 'here (srcloc "file.rkt" 1 0 1 8) 'there)
> (cons 1 (srcloc "file.rkt" 1 0 1 8))
(cons 1 (srcloc "file.rkt" 1 0 1 8))
> (cons 1 (cons 2 (srcloc "file.rkt" 1 0 1 8)))
(list* 1 2 (srcloc "file.rkt" 1 0 1 8))
See also list*.
As shown in the last example, list* is used to abbreviate a series of conses that cannot be
abbreviated using list.
The write and display functions print a pair or list without a leading ', cons, list, or
list*. There is no difference between write and display for a pair or list, except as they
apply to elements of the list:
Examples:
> (write (cons 1 2))
(1 . 2)
54
> (display (list 1 2 "3"))
(1 2 3)
Among the most important predefined procedures on lists are those that iterate through the
list’s elements:
Examples:
> p
(mcons 1 2)
55
> (pair? p)
#f
> (mpair? p)
#t
> (set-mcar! p 0)
> p
(mcons 0 2)
> (write p)
{0 . 2}
§3.10 “Mutable
Pairs and Lists” in
The Racket
Reference provides
3.9 Vectors more on mutable
pairs.
A vector is a fixed-length array of arbitrary values. Unlike a list, a vector supports constant-
time access and update of its elements.
Like strings, a vector is either mutable or immutable, and vectors written directly as expres-
sions are immutable.
Vector can be converted to lists and vice versa via list->vector and vector->list; such
conversions are particularly useful in combination with predefined procedures on lists. When
allocating extra lists seems too expensive, consider using looping forms like for/fold,
which recognize vectors as well as lists.
Example:
56
> (list->vector (map string-titlecase
(vector->list #("three" "blind" "mice"))))
'#("Three" "Blind" "Mice") §3.11 “Vectors” in
The Racket
Reference provides
more on vectors and
3.10 Hash Tables vector procedures.
A hash table implements a mapping from keys to values, where both keys and values can
be arbitrary Scheme values, and access and update to the table are normally constant-time
operations. Keys are compared using equal?, eqv?, or eq?, depending on whether the hash
table is created with make-hash, make-hasheqv, or make-hasheq.
Examples:
The hash, hasheqv, and hasheq functions create immutable hash tables from an initial set
of keys and values, which each value is provided as an argument after its key. Immutable
hash tables can be extended with hash-set, which produces a new immutable hash table in
constant time.
Examples:
57
A literal immutable hash table can be written as an expression by using #hash (for an
equal?-based table), #hasheqv (for an eqv?-based table), or #hasheq (for an eq?-based
table). A parenthesized sequence must immediately follow #hash, #hasheq, or #hasheqv,
where each element is a dotted key–value pair. The #hash, etc. forms implicitly quote their
key and value sub-forms.
Examples:
A mutable hash table can optionally retain its keys weakly, so each mapping is retained only
so long as the key is retained elsewhere.
Examples:
> (collect-garbage)
Beware that even a weak hash table retains its values strongly, as long as the corresponding
key is accessible. This creates a catch-22 dependency when a value refers back to its key, so
that the mapping is retained permanently. To break the cycle, map the key to an ephemeron
that pairs the value with its key (in addition to the implicit pairing of the hash table).
Examples:
58
> (let ([g (gensym)])
(hash-set! ht g (list g)))
> (collect-garbage)
> (collect-garbage)
Examples:
> b
'#&"apple"
> (unbox b)
"apple"
> (set-box! b '(banana boat))
> b
'#&(banana boat) §3.12 “Boxes” in
The Racket
Reference provides
more on boxes and
3.12 Void and Undefined box procedures.
Some procedures or expression forms have no need for a result value. For example, the
display procedure is called only for the side-effect of writing output. In such cases the
59
result value is normally a special constant that prints as #<void>. When the result of an
expression is simply #<void>, the REPL does not print anything.
The void procedure takes any number of arguments and returns #<void>. (That is, the
identifier void is bound to a procedure that returns #<void>, instead of being bound directly
to #<void>.)
Examples:
> (void)
> (void 1 2 3)
A constant that prints as #<undefined> is used as the result of a reference to a local binding
when the binding is not yet initialized. Such early references are not possible for bindings
that correspond to procedure arguments, let bindings, or let* bindings; early reference
requires a recursive binding context, such as letrec or local defines in a procedure body.
Also, early references to top-level and module-level bindings raise an exception, instead of
producing #<undefined>. For these reasons, #<undefined> rarely appears.
(define (strange)
(define x x)
x)
> (strange)
#<undefined>
60
4 Expressions and Definitions
The §2 “Racket Essentials” chapter introduced some of Racket’s syntactic forms: defini-
tions, procedure applications, conditionals, and so on. This section provides more details on
those forms, plus a few additional basic forms.
4.1 Notation
This chapter (and the rest of the documentation) uses a slightly different notation than the
character-based grammars of the §2 “Racket Essentials” chapter. The grammar for a use of
a syntactic form something is shown like this:
The italicized meta-variables in this specification, such as id and an-expr , use the syntax
of Racket identifiers, so an-expr is one meta-variable. A naming convention implicitly
defines the meaning of many meta-variables:
Square brackets in the grammar indicate a parenthesized sequence of forms, where square
brackets are normally used (by convention). That is, square brackets do not mean optional
parts of the syntactic form.
A ... indicates zero or more repetitions of the preceding form, and ...+ indicates one
or more repetitions of the preceding datum. Otherwise, non-italicized identifiers stand for
themselves.
Based on the above grammar, then, here are a few conforming uses of something:
(something [x])
(something [x] (+ 1 2))
(something [x my-favorite-martian x] (+ 1 2) #f)
61
Some syntactic-form specifications refer to meta-variables that are not implicitly defined
and not previously defined. Such meta-variables are defined after the main form, using a
BNF-like format for alternatives:
thing = thing-id
| thing-keyword
The above example says that, within a something-else form, a thing is either an identifier
or a keyword.
The context of an expression determines the meaning of identifiers that appear in the expres-
sion. In particular, starting a module with the language racket, as in
#lang racket
means that, within the module, the identifiers described in this guide start with the meaning
described here: cons refers to the function that creates a pair, car refers to the function that
extracts the first element of a pair, and so on. §3.6 “Symbols”
introduces the
Forms like define, lambda, and let associate a meaning with one or more identifiers; syntax of
identifiers.
that is, they bind identifiers. The part of the program for which the binding applies is the
scope of the binding. The set of bindings in effect for a given expression is the expression’s
environment.
For example, in
#lang racket
(define f
(lambda (x)
(let ([y 5])
(+ x y))))
(f 10)
the define is a binding of f, the lambda has a binding for x, and the let has a binding for
y. The scope of the binding for f is the entire module; the scope of the x binding is (let
([y 5]) (+ x y)); and the scope of the y binding is just (+ x y). The environment of
(+ x y) includes bindings for y, x, and f, as well as everything in racket.
62
A module-level define can bind only identifiers that are not already defined or required
into the module. A local define or other binding forms, however, can give a new local
binding for an identifier that already has a binding; such a binding shadows the existing
binding.
Examples:
(define f
(lambda (append)
(define cons (append "ugly" "confusing"))
(let ([append 'this-was])
(list append cons))))
> (f list)
'(this-was ("ugly" "confusing"))
Similarly, a module-level define can shadow a binding from the module’s language. For
example, (define cons 1) in a racket module shadows the cons that is provided by
racket. Intentionally shadowing a language binding is rarely a good idea—especially for
widely used bindings like cons—but shadowing relieves a programmer from having to avoid
every obscure binding that is provided by a language.
Even identifiers like define and lambda get their meanings from bindings, though they
have transformer bindings (which means that they indicate syntactic forms) instead of value
bindings. Since define has a transformer binding, the identifier define cannot be used by
itself to get a value. However, the normal binding for define can be shadowed.
Examples:
> define
eval:1:0: define: bad syntax
in: define
> (let ([define 5]) define)
5
Again, shadowing standard bindings in this way is rarely a good idea, but the possibility is
an inherent part of Racket’s flexibility.
63
4.3.1 Evaluation Order and Arity
A function call is evaluated by first evaluating the proc-expr and all arg-expr s in order
(left to right). Then, if proc-expr produces a function that accepts as many arguments as
supplied arg-expr s, the function is called. Otherwise, an exception is raised.
Examples:
> (cons 1 null)
'(1)
> (+ 1 2 3)
6
> (cons 1 2 3)
cons: arity mismatch;
the expected number of arguments does not match the given
number
expected: 2
given: 3
arguments...:
1
2
3
> (1 2 3)
application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
arguments...:
2
3
Some functions, such as cons, accept a fixed number of arguments. Some functions, such
as + or list, accept any number of arguments. Some functions accept a range of argument
counts; for example substring accepts either two or three arguments. A function’s arity is
the number of arguments that it accepts.
Some functions accept keyword arguments in addition to by-position arguments. For that
case, an arg can be an arg-keyword arg-expr sequence instead of just a arg-expr : §3.7 “Keywords”
introduces
keywords.
(proc-expr arg ...)
arg = arg-expr
| arg-keyword arg-expr
64
For example,
(go "super.rkt" #:mode 'fast)
calls the function bound to go with "super.rkt" as a by-position argument, and with 'fast
as an argument associated with the #:mode keyword. A keyword is implicitly paired with
the expression that follows it.
The order of keyword arg s determines the order in which arg-expr s are evaluated, but a
function accepts keyword arguments independent of their position in the argument list. The
above call to go can be equivalently written
(go #:mode 'fast "super.rkt")
§2.7 “Procedure
Applications and
#%app” in The
Racket Reference
4.3.3 The apply Function provides more on
procedure
applications.
The syntax for function calls supports any number of arguments, but a specific call always
specifies a fixed number of arguments. As a result, a function that takes a list of arguments
cannot directly apply a function like + to all of the items in a list:
(define (avg lst) ; doesn't work...
(/ (+ lst) (length lst)))
65
The apply function offers a way around this restriction. It takes a function and a list argu-
ment, and it applies the function to the values in the list:
(define (avg lst)
(/ (apply + lst) (length lst)))
As a convenience, the apply function accepts additional arguments between the function
and the list. The additional arguments are effectively consed onto the argument list:
(define (anti-sum lst)
(apply - 0 lst))
The apply function accepts keyword arguments, too, and it passes them along to the called
function:
(apply go #:mode 'fast '("super.rkt"))
(apply go '("super.rkt") #:mode 'fast)
Keywords that are included in apply’s list argument do not count as keyword arguments for
the called function; instead, all arguments in this list are treated as by-position arguments.
To pass a list of keyword arguments to a function, use the keyword-apply function, which
accepts a function to apply and three lists. The first two lists are in parallel, where the first
list contains keywords (sorted by keyword<), and the second list contains a corresponding
argument for each keyword. The third list contains by-position function arguments, as for
apply.
(keyword-apply go
'(#:mode)
'(fast)
'("super.rkt"))
A lambda expression creates a function. In the simplest case, a lambda expression has the
form
66
(lambda (arg-id ...)
body ...+)
(lambda rest-id
body ...+)
That is, a lambda expression can have a single rest-id that is not surrounded by parenthe-
ses. The resulting function accepts any number of arguments, and the arguments are put into
a list bound to rest-id .
Examples:
> ((lambda x x)
1 2 3)
'(1 2 3)
> ((lambda x x))
'()
> ((lambda x (car x))
1 2 3)
1
67
Functions with a rest-id often use apply to call another function that accepts any number
of arguments. §4.3.3 “The apply
Function” describes
Examples: apply.
(define max-mag
(lambda nums
(apply max (map magnitude nums))))
> (max 1 -2 0)
1
> (max-mag 1 -2 0)
2
The lambda form also supports required arguments combined with a rest-id :
The result of this form is a function that requires at least as many arguments as arg-id s,
and also accepts any number of additional arguments.
Examples:
(define max-mag
(lambda (num . nums)
(apply max (map magnitude (cons num nums)))))
> (max-mag 1 -2 0)
2
> (max-mag)
max-mag: arity mismatch;
the expected number of arguments does not match the given
number
expected: at least 1
given: 0
A rest-id variable is sometimes called a rest argument, because it accepts the “rest” of the
function arguments.
Instead of just an identifier, an argument (other than a rest argument) in a lambda form can
be specified with an identifier and a default value:
68
(lambda gen-formals
body ...+)
arg = arg-id
| [arg-id default-expr ]
An argument of the form [arg-id default-expr] is optional. When the argument is not
supplied in an application, default-expr produces the default value. The default-expr
can refer to any preceding arg-id , and every following arg-id must have a default as well.
Examples:
(define greet
(lambda (given [surname "Smith"])
(string-append "Hello, " given " " surname)))
(define greet
(lambda (given [surname (if (equal? given "John")
"Doe"
"Smith")])
(string-append "Hello, " given " " surname)))
69
(lambda gen-formals
body ...+)
arg = arg-id
| [arg-id default-expr ]
| arg-keyword arg-id
| arg-keyword [arg-id default-expr ]
(define greet
(lambda (given #:last surname)
(string-append "Hello, " given " " surname)))
Examples:
(define greet
(lambda (#:hi [hi "Hello"] given #:last [surname "Smith"])
(string-append hi ", " given " " surname)))
The lambda form does not directly support the creation of a function that accepts “rest”
keywords. To construct a function that accepts all keyword arguments, use make-keyword-
70
procedure. The function supplied to make-keyword-procedure receives keyword argu-
ments through parallel lists in the first two (by-position) arguments, and then all by-position
arguments from an application as the remaining by-position arguments. §4.3.3 “The apply
Function”
Examples: introduces
keyword-apply.
(define (trace-wrap f)
(make-keyword-procedure
(lambda (kws kw-args . rest)
(printf "Called with ∼s ∼s ∼s\n" kws kw-args rest)
(keyword-apply f kws kw-args rest))))
(case-lambda
[formals body ...+]
...)
where each [formals body ...+] is analogous to (lambda formals body ...+).
Applying a function produced by case-lambda is like applying a lambda for the first case
that matches the number of given arguments.
Examples:
(define greet
(case-lambda
[(name) (string-append "Hello, " name)]
[(given surname) (string-append "Hello, " given "
" surname)]))
71
> (greet "John" "Smith")
"Hello, John Smith"
> (greet)
greet: arity mismatch;
the expected number of arguments does not match the given
number
given: 0
(define id expr )
Examples:
> salutation
"Hi"
Examples:
72
> (greet "John")
"Hi, John"
The function shorthand via define also supports a “rest” argument (i.e., a final argument to
collect extra arguments in a list):
which is a shorthand
Examples:
(define (avg . l)
(/ (apply + l) (length l)))
> (avg 1 2 3)
2
Consider the following make-add-suffix function that takes a string and returns another
function that takes a string:
(define make-add-suffix
(lambda (s2)
(lambda (s) (string-append s s2))))
Although it’s not common, result of make-add-suffix could be called directly, like this:
73
> ((make-add-suffix "!") "hello")
"hello!"
In a sense, make-add-suffix is a function takes two arguments, but it takes them one at a
time. A function that takes some of its arguments and returns a function to consume more is
sometimes called a curried function.
This shorthand reflects the shape of the function call (make-add-suffix "!"). The de-
fine form further supports a shorthand for defining curried functions that reflects nested
function calls:
(define ((make-add-suffix s2) s)
(string-append s s2))
head = id
| (head args )
The expansion of this shorthand has one nested lambda form for each head in the definition,
where the innermost head corresponds to the outermost lambda.
74
4.5.3 Multiple Values and define-values
A Racket expression normally produces a single result, but some expressions can produce
multiple results. For example, quotient and remainder each produce a single value, but
quotient/remainder produces the same two values at once:
> (quotient 13 3)
4
> (remainder 13 3)
1
> (quotient/remainder 13 3)
4
1
As shown above, the REPL prints each result value on its own line.
Multiple-valued functions can be implemented in terms of the values function, which takes
any number of values and returns them as the results:
> (values 1 2 3)
1
2
3
The define-values form binds multiple identifiers at once to multiple results produced
from a single expression:
The number of results produced by the expr must match the number of id s.
Examples:
75
(define-values (given surname) (split-name "Adam Smith"))
> given
"Adam"
> surname
"Smith"
A define form (that is not a function shorthand) is equivalent to a define-values form
with a single id . §2.14 “Definitions:
define,
define-syntax,
...” in The Racket
4.5.4 Internal Definitions Reference provides
more on definitions.
When the grammar for a syntactic form specifies body , then the corresponding form can be
either a definition or an expression. A definition as a body is an internal definition.
Expressions and internal definitions in a body sequence can be mixed, as long as the last
body is an expression.
(lambda gen-formals
body ...+)
76
(define (log-it what)
(printf "∼a\n" what))
(call n))
Internal definitions in a particular body sequence are mutually recursive; that is, any defini-
tion can refer to any other definition—as long as the reference isn’t actually evaluated before
its definition takes place. If a definition is referenced too early, the result is a special value
#<undefined>.
Examples:
(define (weird)
(define x x)
x)
> (weird)
#<undefined>
A sequence of internal definitions using just define is easily translated to an equivalent
letrec form (as introduced in the next section). However, other definition forms can appear
as a body , including define-values, struct (see §5 “Programmer-Defined Datatypes”)
or define-syntax (see §16 “Macros”). §1.2.3.7 “Internal
Definitions” in The
Racket Reference
documents the fine
4.6 Local Binding points of internal
definitions.
Although internal defines can be used for local binding, Racket provides three forms that
give the programmer more control over bindings: let, let*, and letrec.
The id s are bound “in parallel.” That is, no id is bound in the right-hand side expr for any
id , but all are available in the body . The id s must be different from each other.
Examples:
> (let ([me "Bob"])
me)
"Bob"
77
> (let ([me "Bob"]
[myself "Robert"]
[I "Bobby"])
(list me myself I))
'("Bob" "Robert" "Bobby")
> (let ([me "Bob"]
[me "Robert"])
me)
eval:3:0: let: duplicate identifier
at: me
in: (let ((me "Bob") (me "Robert")) me)
The fact that an id ’s expr does not see its own binding is often useful for wrappers that
must refer back to the old value:
Occasionally, the parallel nature of let bindings is convenient for swapping or rearranging
a set of bindings:
The characterization of let bindings as “parallel” is not meant to imply concurrent evalua-
tion. The expr s are evaluated in order, even though the bindings are delayed until all expr s
are evaluated.
78
The difference is that each id is available for use in later expr s, as well as in the body .
Furthermore, the id s need not be distinct, and the most recent binding is the visible one.
Examples:
> (let* ([x (list "Borroughs")]
[y (cons "Rice" x)]
[z (cons "Edgar" y)])
(list x y z))
'(("Borroughs") ("Rice" "Borroughs") ("Edgar" "Rice" "Borroughs"))
> (let* ([name (list "Borroughs")]
[name (cons "Rice" name)]
[name (cons "Edgar" name)])
name)
'("Edgar" "Rice" "Borroughs")
In other words, a let* form is equivalent to nested let forms, each with a single binding:
> (let ([name (list "Borroughs")])
(let ([name (cons "Rice" name)])
(let ([name (cons "Edgar" name)])
name)))
'("Edgar" "Rice" "Borroughs")
While let makes its bindings available only in the body s, and let* makes its bind-
ings available to any later binding expr , letrec makes its bindings available to all other
expr s—even earlier ones. In other words, letrec bindings are recursive.
The expr s in a letrec form are most often lambda forms for recursive and mutually re-
cursive functions:
> (letrec ([swing
(lambda (t)
(if (eq? (car t) 'tarzan)
(cons 'vine
(cons 'tarzan (cddr t)))
(cons (car t)
(swing (cdr t)))))])
(swing '(vine tarzan vine vine)))
'(vine vine tarzan vine)
79
> (letrec ([tarzan-in-tree?
(lambda (name path)
(or (equal? name "tarzan")
(and (directory-exists? path)
(tarzan-in-directory? path))))]
[tarzan-in-directory?
(lambda (dir)
(ormap (lambda (elem)
(tarzan-in-tree? (path-element-
>string elem)
(build-path dir elem)))
(directory-list dir)))])
(tarzan-in-tree? "tmp" (find-system-path 'temp-dir)))
#f
While the expr s of a letrec form are typically lambda expressions, they can be any ex-
pression. The expressions are evaluated in order, and after each value is obtained, it is
immediately associated with its corresponding id . If an id is referenced before its value is
ready, the result is #<undefined>, just as for internal definitions.
A named let is an iteration and recursion form. It uses the same syntactic keyword let as
for local binding, but an identifier after the let (instead of an immediate open parenthesis)
triggers a different parsing.
That is, a named let binds a function identifier that is visible only in the function’s body,
and it implicitly calls the function with the values of some initial expressions.
Examples:
80
(define (duplicate pos lst)
(let dup ([i 0]
[lst lst])
(cond
[(= i pos) (cons (car lst) lst)]
[else (cons (car lst) (dup (+ i 1) (cdr lst)))])))
Each expr must produce as many values as corresponding id s. The binding rules are the
same for the forms without -values forms: the id s of let-values are bound only in
the body s, the id s of let*-valuess are bound in expr s of later clauses, and the id s of
letrec-values are bound for all expr s.
Example:
> (let-values ([(q r) (quotient/remainder 14 3)])
(list q r))
'(4 2)
4.7 Conditionals
Most functions used for branching, such as < and string?, produce either #t or #f.
Racket’s branching forms, however, treat any value other than #f as true. We say a true
value to mean any value other than #f.
81
This convention for “true value” meshes well with protocols where #f can serve as failure
or to indicate that an optional value is not supplied. (Beware of overusing this trick, and
remember that an exception is usually a better mechanism to report failure.)
For example, the member function serves double duty; it can be used to find the tail of a list
that starts with a particular item, or it can be used to simply check whether an item is present
in a list:
the test-expr is always evaluated. If it produces any value other than #f, then then-expr
is evaluated. Otherwise, else-expr is evaluated.
An if form must have both a then-expr and an else-expr ; the latter is not optional.
To perform (or skip) side-effects based on a test-expr , use when or unless, which we
describe later in §4.8 “Sequencing”.
82
An and form produces #f if any of its expr s produces #f. Otherwise, it produces the value
of its last expr . As a special case, (and) produces #t.
The or form produces #f if all of its expr s produce #f. Otherwise, it produces the first
non-#f value from its exprs. As a special case, (or) produces #f.
Examples:
The cond form chains a series of tests to select a result expression. To a first approximation,
the syntax of cond is as follows: §2.12
“Conditionals: if,
cond, and, and or”
in The Racket
(cond [test-expr expr ...+] Reference also
...) documents cond.
Each test-expr is evaluated in order. If it produces #f, the corresponding expr s are
ignored, and evaluation proceeds to the next test-expr . As soon as a test-expr produces
a true value, its expr s are evaluated to produce the result for the cond form, and no further
test-expr s are evaluated.
The last test-expr in a cond can be replaced by else. In terms of evaluation, else serves
as a synonym for #t, but it clarifies that the last clause is meant to catch all remaining cases.
If else is not used, then it is possible that no test-expr s produce a true value; in that case,
the result of the cond expression is #<void>.
Examples:
83
> (cond
[(= 2 3) (error "wrong!")]
[(= 2 2) 'ok])
'ok
> (cond
[(= 2 3) (error "wrong!")])
> (cond
[(= 2 3) (error "wrong!")]
[else 'ok])
'ok
(define (got-milk? lst)
(cond
[(null? lst) #f]
[(eq? 'milk (car lst)) #t]
[else (got-milk? (cdr lst))]))
The => variant captures the true result of its test-expr and passes it to the result of the
proc-expr , which must be a function of one argument.
Examples:
> (define (after-groucho lst)
(cond
[(member "Groucho" lst) => cdr]
[else (error "not there")]))
84
A clause that includes only a test-expr is rarely used. It captures the true result of the
test-expr , and simply returns the result for the whole cond expression.
4.8 Sequencing
Racket programmers prefer to write programs with as few side-effects as possible, since
purely functional code is more easily tested and composed into larger programs. Interaction
with the external environment, however, requires sequencing, such as when writing to a
display, opening a graphical window, or manipulating a file on disk.
The expr s are evaluated in order, and the result of all but the last expr is ignored. The result
from the last expr is the result of the begin form, and it is in tail position with respect to
the begin form.
Examples:
> (print-triangle 4)
****
***
**
*
Many forms, such as lambda or cond support a sequence of expressions even without a
begin. Such positions are sometimes said to have an implicit begin.
Examples:
85
(define (print-triangle height)
(cond
[(positive? height)
(display (make-string height #\*))
(newline)
(print-triangle (sub1 height))]))
> (print-triangle 4)
****
***
**
*
The begin form is special at the top level, at module level, or as a body after only internal
definitions. In those positions, instead of forming an expression, the content of begin is
spliced into the surrounding context.
Example:
This splicing behavior is mainly useful for macros, as we discuss later in §16 “Macros”.
The difference is that begin0 returns the result of the first expr, instead of the result of
the last expr. The begin0 form is useful for implementing side-effects that happen after a
computation, especially in the case where the computation produces an unknown number of
results.
Examples:
86
(begin0
(thunk)
(printf "End..: ∼s\n" (current-inexact-milliseconds))))
If test-expr produces a true value, then all of the then-expr s are evaluated. The result of
the last then-expr is the result of the when form. Otherwise, no then-expr s are evaluated
and the result is #<void>.
The difference is that the test-expr result is inverted: the then-expr s are evaluated only
if the test-expr result is #f.
Examples:
87
> (enumerate '("Larry" "Curly" "Moe"))
Larry, Curly, and Moe.
> (print-triangle 4)
****
***
**
*
A set! expression evaluates expr and changes id (which must be bound in the enclosing
environment) to the resulting value. The result of the set! expression itself is #<void>.
Examples:
88
(define (make-running-total)
(let ([n 0])
(lambda ()
(set! n (+ n 1))
n)))
(define win (make-running-total))
(define lose (make-running-total))
> (win)
1
> (win)
2
> (lose)
1
> (win)
3
Although using set! is sometimes appropriate, Racket style generally discourages the use
of set!. The following guidelines may help explain when using set! is appropriate.
> (greet)
> result
"Hello, John"
Ok example:
89
> (greet "Anna")
"Hello, Anna"
90
(define (sum lst)
(apply + lst))
> (next-number!)
1
> (next-number!)
2
> (next-number!)
3
All else being equal, a program that uses no assignments or mutation is always preferable
to one that uses assignments or mutation. While side effects are to be avoided, however,
they should be used if the resulting code is significantly more readable or if it implements a
significantly better algorithm.
The use of mutable values, such as vectors and hash tables, raises fewer suspicions about
the style of a program than using set! directly. Nevertheless, simply replacing set!s in a
program with a vector-set!s obviously does not improve the style of the program.
This form is equivalent to using let-values to receive multiple results from expr , and
then assigning the results individually to the id s using set!.
Examples:
(define game
(let ([w 0]
[l 0])
(lambda (win?)
(if win?
(set! w (+ w 1))
(set! l (+ l 1)))
(begin0
(values w l)
; swap sides...
(set!-values (w l) (values l w))))))
The syntax of a datum is technically specified as anything that the read function parses as
a single element. The value of the quote form is the same value that read would produce
given datum .
The datum can be a symbol, a boolean, a number, a (character or byte) string, a character,
a keyword, an empty list, a pair (or list) containing more such values, a vector containing
more such values, a hash table containing more such values, or a box containing another
such value.
92
Examples:
> (quote apple)
'apple
> (quote #t)
#t
> (quote 42)
42
> (quote "hello")
"hello"
> (quote ())
'()
> (quote ((1 2 3) #("z" x) . the-end))
'((1 2 3) #("z" x) . the-end)
> (quote (1 2 . (3)))
'(1 2 3)
As the last example above shows, the datum does not have to match the normalized printed
form of a value. A datum cannot be a printed representation that starts with #<, so it cannot
be #<void>, #<undefined>, or a procedure.
The quote form is rarely used for a datum that is a boolean, number, or string by itself,
since the printed forms of those values can already be used as constants. The quote form is
more typically used for symbols and lists, which have other meanings (identifiers, function
calls, etc.) when not quoted.
An expression
'datum
is a shorthand for
(quote datum )
and this shorthand is almost always used instead of quote. The shorthand applies even
within the datum , so it can produce a list containing quote. §1.3.7 “Reading
Quotes” in The
Examples: Racket Reference
provides more on
> 'apple the ' shorthand.
'apple
> '"hello"
"hello"
> '(1 2 3)
'(1 2 3)
> (display '(you can 'me))
(you can (quote me))
93
4.11 Quasiquoting: quasiquote and `
§2.20
“Quasiquoting:
The quasiquote form is similar to quote: quasiquote,
unquote, and
unquote-splicing”
in The Racket
(quasiquote datum ) Reference also
documents
quasiquote.
However, for each (unquote expr ) that appears within the datum , the expr is evaluated
to produce a value that takes the place of the unquote sub-form.
Example:
Examples:
> (deep 8)
'(8 (7 (6 (5 (4 (3 (2 (1 0))))))))
Or even to cheaply construct expressions programmatically. (Of course, 9 times out of 10,
you should be using a macro to do this (the 10th time being when you’re working through a
textbook like PLAI).)
Examples:
94
> (define (make-sum n)
(cond
[(= n 1) (n->var 1)]
[else
(quasiquote (+ (unquote (n->var n))
(unquote (make-sum (- n 1)))))]))
> (build-exp 3)
'(let ((x3 3)) (let ((x2 2)) (let ((x1 1)) (+ x3 (+ x2 x1)))))
The unquote-splicing form is similar to unquote, but its expr must produce a list, and
the unquote-splicing form must appear in a context that produces either a list or a vector.
As the name suggests, the resulting list is spliced into the context of its use.
Example:
Using splicing we can revise the construction of our example expressions above to have just
a single let expression and a single + expression.
Examples:
95
> (build-exp 3)
'(let ((x1 1) (x2 2) (x3 3)) (+ x1 x2 x3))
If a quasiquote form appears within an enclosing quasiquote form, then the inner
quasiquote effectively cancels one layer of unquote and unquote-splicing forms, so
that a second unquote or unquote-splicing is needed.
Examples:
> (quasiquote (1 2 (quasiquote (unquote (+ 1 2)))))
'(1 2 (quasiquote (unquote (+ 1 2))))
> (quasiquote (1 2 (quasiquote (unquote (unquote (+ 1 2))))))
'(1 2 (quasiquote (unquote 3)))
> (quasiquote (1 2 (quasiquote ((unquote (+ 1 2)) (unquote (unquote (- 5 1)))))))
'(1 2 (quasiquote ((unquote (+ 1 2)) (unquote 4))))
The evaluations above will not actually print as shown. Instead, the shorthand form of
quasiquote and unquote will be used: ` (i.e., a backquote) and , (i.e., a comma). The
same shorthands can be used in expressions:
Example:
> `(1 2 `(,(+ 1 2) ,,(- 5 1)))
'(1 2 `(,(+ 1 2) ,4))
The shorthand form of unquote-splicing is ,@:
Example:
> `(1 2 ,@(list (+ 1 2) (- 5 1)))
'(1 2 3 4)
The case form dispatches to a clause by matching the result of an expression to the values
for the clause:
(case expr
[(datum ...+) expr ...+]
...)
Each datum will be compared to the result of the first expr using eqv?. Since eqv? doesn’t
work on many kinds of values, notably strings and lists, each datum is typically a number,
symbol, or boolean.
Multiple datum s can be supplied for each clause, and the corresponding expr is evaluated
if any of the datum s match.
96
Example:
The last clause of a case form can use else, just like cond:
Example:
For more general pattern matching, use match, which is introduced in §12 “Pattern Match-
ing”.
97
car: contract violation
expected: pair?
given: 1000000...
> (location)
"here"
The parameterize form is not a binding form like let; each use of location above refers
directly to the original definition. A parameterize form adjusts the value of a parameter
during the whole time that the parameterize body is evaluated, even for uses of the pa-
rameter that are textually outside of the parameterize body:
98
> (would-you-could-you?)
#f
> (parameterize ([location "on a bus"])
(would-you-could-you?))
#t
If a use of a parameter is textually inside the body of a parameterize but not evaluated be-
fore the parameterize form produces a value, then the use does not see the value installed
by the parameterize form:
The current binding of a parameter can be adjusted imperatively by calling the parameter as
a function with a value. If a parameterize has adjusted the value of the parameter, then
directly applying the parameter procedure affects only the value associated with the active
parameterize:
> (location)
"here"
> (parameterize ([location "on a train"])
(list (location)
(begin (try-again! "in a boat")
(location))))
'("on a train" "in a boat")
> (location)
"here"
It may seem that variables and set! can solve many of the same problems that parameters
solve. For example, lokation could be defined as a string, and set! could be used to adjust
its value:
99
> (define (would-ya-could-ya?)
(and (not (equal? lokation "here"))
(not (equal? lokation "there"))))
> (would-ya-could-ya?)
#t
• The parameterize form helps automatically reset the value of a parameter when
control escapes due to an exception. Adding exception handlers and other forms to
rewind a set! is relatively tedious.
• Parameters work nicely with tail calls (see §2.3.3 “Tail Recursion”). The last body in
a parameterize form is in tail position with respect to the parameterize form.
• Parameters work properly with threads (see §10.1 “Threads”). The parameterize
form adjusts the value of a parameter only for evaluation in the current thread, which
avoids race conditions with other threads.
100
5 Programmer-Defined Datatypes
§4 “Structures” in
The Racket
New datatypes are normally created with the struct form, which is the topic of this chapter. Reference also
The class-based object system, which we defer to §13 “Classes and Objects”, offers an al- documents structure
types.
ternate mechanism for creating new datatypes, but even classes and objects are implemented
in terms of structure types.
Examples:
> (posn 1 2)
#<posn>
• struct-id ? : a predicate function that takes a single argument and returns #t if it is
an instance of the structure type, #f otherwise.
Examples:
> (posn? 3)
#f
> (posn? (posn 1 2))
#t
• struct-id -field-id : for each field-id , an accessor that extracts the value of
the corresponding field from an instance of the structure type.
Examples:
101
• struct:struct-id : a structure type descriptor, which is a value that represents the
structure type as a first-class value (with #:super, as discussed later in §5.8 “More
Structure Type Options”).
A struct form places no constraints on the kinds of values that can appear for fields in an
instance of the structure type. For example, (posn "apple" #f) produces an instance of
posn, even though "apple" and #f are not valid coordinates for the obvious uses of posn
instances. Enforcing constraints on field values, such as requiring them to be numbers, is
normally the job of a contract, as discussed later in §7 “Contracts”.
The struct-copy form clones a structure and optionally updates specified fields in the
clone. This process is sometimes called a functional update, because the result is a structure
with updated field values. but the original structure is not modified.
The struct-id that appears after struct-copy must be a structure type name bound by
struct (i.e., the name that cannot be used directly as an expression). The struct-expr
must produce an instance of the structure type. The result is a new instance of the structure
type that is like the old one, except that the field indicated by each field-id gets the value
of the corresponding expr .
Examples:
> (define p1 (posn 1 2))
An extended form of struct can be used to define a structure subtype, which is a structure
type that extends an existing structure type:
102
The super-id must be a structure type name bound by struct (i.e., the name that cannot
be used directly as an expression).
Examples:
A structure subtype inherits the fields of its supertype, and the subtype constructor accepts
the values for the subtype fields after values for the supertype fields. An instance of a struc-
ture subtype can be used with the predicate and accessors of the supertype.
Examples:
> p
#<3d-posn>
> (posn? p)
#t
> (posn-x p)
1
> (3d-posn-z p)
3
an instance of the structure type prints in a way that does not show any information about
the fields’ values. That is, structure types by default are opaque. If the accessors and mu-
tators of a structure type are kept private to a module, then no other module can rely on the
representation of the type’s instances.
To make a structure type transparent, use the #:transparent keyword after the field-name
sequence:
(struct posn (x y)
#:transparent)
> (posn 1 2)
(posn 1 2)
103
An instance of a transparent structure type prints like a call to the constructor, so that it shows
the structures field values. A transparent structure type also allows reflective operations, such
as struct? and struct-info, to be used on its instances (see §15 “Reflection and Dynamic
Evaluation”).
Structure types are opaque by default, because opaque structure instances provide more en-
capsulation guarantees. That is, a library can use an opaque structure to encapsulate data,
and clients of the library cannot manipulate the data in the structure except as allowed by the
library.
To support instances comparisons via equal? without making the structure type transparent,
you can use the #:methods keyword, gen:equal+hash, and implement three methods:
104
(define (hash2-proc a hash2-recur)
; compute secondary hash code of a
(+ (hash2-recur (lead-width a))
(hash2-recur (lead-height a))))])
The first function in the list implements the equal? test on two leads; the third argument to
the function is used instead of equal? for recursive equality testing, so that data cycles can
be handled correctly. The other two functions compute primary and secondary hash codes
for use with hash tables:
The first function provided with gen:equal+hash is not required to recursively compare
the fields of the structure. For example, a structure type representing a set might implement
equality by checking that the members of the set are the same, independent of the order of
elements in the internal representation. Just take care that the hash functions produce the
same value for any two structure types that are supposed to be equivalent.
Each time that a struct form is evaluated, it generates a structure type that is distinct from
all existing structure types, even if some other structure type has the same name and fields.
This generativity is useful for enforcing abstractions and implementing programs such as
interpreters, but beware of placing a struct form in positions that are evaluated multiple
times.
Examples:
105
[else (cons (fish (* 2 (fish-size (car lst))))
lst)]))
Although a transparent structure type prints in a way that shows its content, the printed form
of the structure cannot be used in an expression to get the structure back, unlike the printed
form of a number, string, symbol, or list.
A prefab (“previously fabricated”) structure type is a built-in type that is known to the Racket
printer and expression reader. Infinitely many such types exist, and they are indexed by
name, field count, supertype, and other such details. The printed form of a prefab structure
is similar to a vector, but it starts #s instead of just #, and the first element in the printed
form is the prefab structure type’s name.
The following examples show instances of the sprout prefab structure type that has one
field. The first instance has a field value 'bean, and the second has field value 'alfalfa:
Like numbers and strings, prefab structures are “self-quoting,” so the quotes above are op-
tional:
106
> #s(sprout bean)
'#s(sprout bean)
When you use the #:prefab keyword with struct, instead of generating a new structure
type, you obtain bindings that work with the existing prefab structure type:
> (define lunch '#s(sprout bean))
The field name kind above does not matter for finding the prefab structure type; only the
name sprout and the number of fields matters. At the same time, the prefab structure type
sprout with three fields is a different structure type than the one with a single field:
> (sprout? #s(sprout bean #f 17))
#f
> (struct sprout (kind yummy? count) #:prefab) ; redefine
A prefab structure type can have another prefab structure type as its supertype, it can have
mutable fields, and it can have auto fields. Variations in any of these dimensions correspond
to different prefab structure types, and the printed form of the structure type’s name encodes
all of the relevant details.
> (struct building (rooms [location #:mutable]) #:prefab)
Every prefab structure type is transparent—but even less abstract than a transparent type,
because instances can be created without any access to a particular structure-type declaration
107
or existing examples. Overall, the different options for structure types offer a spectrum of
possibilities from more abstract to more convenient:
• Opaque (the default) : Instances cannot be inspected or forged without access to the
structure-type declaration. As discussed in the next section, constructor guards and
properties can be attached to the structure type to further protect or to specialize the
behavior of its instances.
• Transparent : Anyone can inspect or create an instance without access to the structure-
type declaration, which means that the value printer can show the content of an in-
stance. All instance creation passes through a constructor guard, however, so that the
content of an instance can be controlled, and the behavior of instances can be spe-
cialized through properties. Since the structure type is generated by its definition,
instances cannot be manufactured simply through the name of the structure type, and
therefore cannot be generated automatically by the expression reader.
• Prefab : Anyone can inspect or create an instance at any time, without prior access
to a structure-type declaration or an example instance. Consequently, the expression
reader can manufacture instances directly. The instance cannot have a constructor
guard or properties.
Since the expression reader can generate prefab instances, they are useful when convenient
serialization is more important than abstraction. Opaque and transparent structures also
can be serialized, however, if they are defined with define-serializable-struct as
described in §8.4 “Datatypes and Serialization”.
The full syntax of struct supports many options, both at the structure-type level and at the
level of individual fields:
maybe-super =
| super-id
field = field-id
| [field-id field-option ...]
108
#:mutable
> (dot-x d)
1
> (set-dot-x! d 10)
> (dot-x d)
10
#:transparent
#:inspector inspector-expr
109
#:prefab
Accesses a built-in structure type, as discussed in a previous section,
§5.7 “Prefab Structure Types”.
#:auto-value auto-expr
Specifies a value to be used for all automatic fields in the structure
type, where an automatic field is indicated by the #:auto field op-
tion. The constructor procedure does not accept arguments for auto-
matic fields. Automatic fields are implicitly mutable (via reflective
operations), but mutator functions are bound only if #:mutator is
also specified.
Examples:
> (struct posn (x y [z #:auto])
#:transparent
#:auto-value 0)
> (posn 1 2)
(posn 1 2 0)
#:guard guard-expr
Specifies a constructor guard procedure to be called whenever an
instance of the structure type is created. The guard takes as many ar-
guments as non-automatic fields in the structure type, plus one more
for the name of the instantiated type (in case a sub-type is instanti-
ated, in which case it’s best to report an error using the sub-type’s
name). The guard should return the same number of values as given,
minus the name argument. The guard can raise an exception if one of
the given arguments is unacceptable, or it can convert an argument.
Examples:
> (struct thing (name)
#:transparent
#:guard (lambda (name type-name)
(cond
[(string? name) name]
[(symbol? name) (symbol-
>string name)]
[else (error type-name
"bad name:
∼e"
name)])))
110
> (thing "apple")
(thing "apple")
> (thing 'apple)
(thing "apple")
> (thing 1/2)
thing: bad name: 1/2
The guard is called even when subtype instances are created. In that
case, only the fields accepted by the constructor are provided to the
guard (but the subtype’s guard gets both the original fields and fields
added by the subtype).
Examples:
Associates a property and value with the structure type. For exam-
ple, the prop:procedure property allows a structure instance to be
used as a function; the property value determines how a call is im-
plemented when using the structure as a function.
Examples:
111
(define joe-greet (greeter "Joe"))
#:super super-expr
112
6 Modules
Modules let you organize Racket code into multiple files and reusable libraries.
Each Racket module typically resides in its own file. For example, suppose the file
"cake.rkt" contains the following module:
"cake.rkt"
#lang racket
(provide print-cake)
Then, other modules can import "cake.rkt" to use the print-cake function, since the
provide line in "cake.rkt" explicitly exports the definition print-cake. The show func-
tion is private to "cake.rkt" (i.e., it cannot be used from other modules), since show is not
exported.
"random-cake.rkt"
#lang racket
(require "cake.rkt")
The relative reference "cake.rkt" in the import (require "cake.rkt") works if the
"cake.rkt" and "random-cake.rkt" modules are in the same directory. Unix-style rela-
tive paths are used for relative module references on all platforms, much like relative URLs
in HTML pages.
113
6.1.1 Organizing Modules
The "cake.rkt" and "random-cake.rkt" example demonstrates the most common way
to organize a program into modules: put all module files in a single directory (perhaps with
subdirectories), and then have the modules reference each other through relative paths. A
directory of modules can act as a project, since it can be moved around on the filesystem or
copied to other machines, and relative paths preserve the connections among modules.
As another example, if you are building a candy-sorting program, you might have a
main "sort.rkt" module that uses other modules to access a candy database and a
control sorting machine. If the candy-database module itself is organized into sub-
modules that handle barcode and manufacturer information, then the database mod-
ule could be "db/lookup.rkt" that uses helper modules "db/barcodes.rkt" and
"db/makers.rkt". Similarly, the sorting-machine driver "machine/control.rkt"
might use helper modules "machine/sensors.rkt" and "machine/actuators.rkt".
sort.rkt db machine
lookup.rkt control.rkt
"sort.rkt"
#lang racket
(require "db/lookup.rkt" "machine/control.rkt")
....
114
The "db/lookup.rkt" module similarly uses paths relative to its own source to access the
"db/barcodes.rkt" and "db/makers.rkt" modules:
"db/lookup.rkt"
#lang racket
(require "barcode.rkt" "makers.rkt")
....
"machine/control.rkt"
#lang racket
(require "sensors.rkt" "actuators.rkt")
....
Racket tools all work automatically with relative paths. For example,
racket sort.rkt
on the comamnd line runs the "sort.rkt" program and automatically loads and compiles
required modules. With a large enough program, compilation from source can take too long,
so use
to compile "sort.rkt" and all its dependencies to bytecode files. Running racket
sort.rkt will automatically use bytecode files when they are present. See §1 “raco
make: Compiling
Source to
Bytecode” for more
6.1.2 Library Collections information on
raco make.
#lang racket
(require racket/date)
When you search the online Racket documentation, the search results indicate the module
that provides each binding. Alternatively, if you reach a binding’s documentation by clicking
on hyperlinks, you can hover over the binding name to find out which modules provide it.
115
A module reference like racket/date looks like an identifier, but it is not treated in the
same way as printf or date->string. Instead, when require sees a module reference
that is unquoted, it converts the reference to a collection-based module path:
• First, if the unquoted path contains no /, then require automatically adds a "/main"
to the reference. For example, (require slideshow) is equivalent to (require
slideshow/main).
• Second, require implicitly adds a ".rkt" suffix to the path.
• Finally, require treats the path as relative to the installation location of the collection,
instead of relative to the enclosing module’s path.
The "racket" collection is located in a directory with the Racket installation. A user-
specific directory can contain additional collections, and even more collection directories
can be specified in configuration files or through the PLTCOLLECTS search path. Try running
the following program to find out how your collection search path is configured:
#lang racket
(require setup/dirs)
Looking back at the candy-sorting example of §6.1.1 “Organizing Modules”, suppose that
modules in "db/" and "machine/" need a common set of helper functions. Helper func-
tions could be put in a "utils/" directory, and modules in "db/" or "machine/" could
access utility modules with relative paths that start "../utils/". As long as a set of mod-
ules work together in a single project, it’s best to stick with relative paths. A programmer
can follow relative-path references without knowing about your Racket configuration.
Some libraries are meant to be used across multiple projects, so that keeping the library
source in a directory with its uses does not make sense. In that case, you have two options:
• Add the library to a new or existing collection. After the library is in a collection, it
can be referenced with an unquoted path, just like libraries that are included with the
Racket distribution.
• Add the library to a new or existing PLaneT package. Libraries in a PLaneT package
are referenced with a path of the form (planet ....) path. See PLaneT:
Automatic Package
Distribution for
more information
116 on PLaneT.
The simplest option is to add a new collection. You could add a new collection by plac-
ing files in the Racket installation or one of the directories reported by (get-collects-
search-dirs). Alternatively, you could add to the list of searched directories by setting
the PLTCOLLECTS environment variable; if you set PLTCOLLECTS, include an empty path in
by starting the value with a colon (Unix and Mac OS X) or semicolon (Windows) so that the
original search paths are preserved. Finally, instead of using one of the default directories or
setting PLTCOLLECTS, you can use raco link.
The raco link command-line tool creates a link from a collection name to a di-
rectory for the collection’s modules. For example, suppose you have a directory
"/usr/molly/bakery" that contains the "cake.rkt" module (from the beginning of this
section) and other related modules. To make the modules available as a "bakery" collec-
tion, use Instead of installing
a single collection
raco link /usr/molly/bakery directory, the
--root or -d flag
for raco link can
Afterward, (require bakery/cake) from any module will import the print-cake func- install a directory
tion from "/usr/molly/bakery/cake.rkt". that contains
collections, much
To make a collection name different from the name of the directory that contains the col- like adding to
PLTCOLLECTS.
lection’s modules, use the --name or -n option for raco link. By default, raco link
installs a collection link only for the current user, but you can supply the --installation
or -i flag to install the link for all users of your Racket installation. See §2 “raco
link: Library
If you intend to distribute your library collection to others, choose the collection name care- Collection Links”
for more
fully. The collection namespace is hierarchical, but (unlike PLaneT) the collection system information on
has no built-in feature to avoid conflicts from different producers or different versions. Con- raco link.
sider putting one-off libraries under some top-level name like "molly" that identifies the
producer. Use a collection name like "bakery" when producing the definitive collection of
baked-goods libraries.
After your libraries are put in a collection you can still use raco make to compile the li-
brary sources, but it’s better and more convenient to use raco setup. The raco setup
command takes a collection name (as opposed to a file name) and compiles all libraries
within the collection. In addition, it can build documentation for the collection and add it to
the documentation index, as specified by a "info.rkt" module in the collection. See §8
“raco setup: Installation Management” for more information on raco setup.
The #lang at the start of a module file begins a shorthand for a module form, much like '
is a shorthand for a quote form. Unlike ', the #lang shorthand does not work well in a
REPL, in part because it must be terminated by an end-of-file, but also because the longhand
expansion of #lang depends on the name of the enclosing file.
117
6.2.1 The module Form
The longhand form of a module declaration, which works in a REPL as well as a file, is
where the name-id is a name for the module, initial-module-path is an initial import,
and each decl is an import, export, definition, or expression. In the case of a file, name-id
normally matches the name of the containing file, minus its directory path or file extension,
but name-id is ignored when the module is required through its file’s path.
The initial-module-path is needed because even the require form must be imported
for further use in the module body. In other words, the initial-module-path import
bootstraps the syntax that is available in the body. The most commonly used initial-
module-path is racket, which supplies most of the bindings described in this guide,
including require, define, and provide. Another commonly used initial-module-
path is racket/base, which provides less functionality, but still much of the most com-
monly needed functions and syntax.
For example, the "cake.rkt" example of the previous section could be written as
(define (print-cake n)
(show " ∼a " n #\.)
(show " .-∼a-. " n #\|)
(show " | ∼a | " n #\space)
(show "---∼a---" n #\-))
Furthermore, this module form can be evaluated in a REPL to declare a cake module that
is not associated with any file. To refer to such an unassociated module, quote the module
name:
Examples:
> (print-cake 3)
118
...
.-|||-.
| |
---------
Declaring a module does not immediately evaluate the body definitions and expressions of
the module. The module must be explicitly required at the top level to trigger evaluation.
After evaluation is triggered once, later requires do not re-evaluate the module body.
Examples:
> (module hi racket
(printf "Hello\n"))
The body of a #lang shorthand has no specific syntax, because the syntax is determined by
the language name that follows #lang.
where name is derived from the name of the file that contains the #lang form.
The #lang racket/base form has the same syntax as #lang racket, except that the long-
hand expansion uses racket/base instead of racket. The #lang honu form, in contrast,
has a completely different syntax that doesn’t even look like Racket, and which we do not
attempt to describe in this guide.
Unless otherwise specified, a module that is documented as a “language” using the #lang
notation will expand to module in the same way as #lang racket. The documented lan-
guage name can be used directly with module or require, too.
119
6.2.3 Submodules
A module form can be nested within a module, in which case the nested module form
declares a submodule. Submodules can be referenced directly by the enclosing module
using a quoted name. The following example prints "Tony" by importing tiger from the
zoo submodule:
"park.rkt"
#lang racket
(require 'zoo)
tiger
Running a module does not necessarily run its submodules. In the above example, running
"park.rkt" runs its submodule zoo only because the "park.rkt" module requires the
zoo submodule. Otherwise, a module and each of its submodules can be run independently.
Furthermore, if "park.rkt" is compiled to a bytecode file (via raco make), then the code
for "park.rkt" or the code for zoo can be loaded independently.
Submodules can be nested within submodules, and a submodule can be referenced directly
by a module other than its enclosing module by using a submodule path.
The module* form differs from module in that it inverts the possibilities for reference be-
tween the submodule and enclosing module:
• A submodule declared with module can be required by its enclosing module, but the
submodule cannot require the enclosing module or lexically reference the enclosing
module’s bindings.
• A submodule declared with module* can require its enclosing module, but the en-
closing module cannot require the submodule.
120
One use of submodule declared with module* and #f is to export additional bindings
through a submodule that are not normally exported from the module:
"cake.rkt"
#lang racket
(provide print-cake)
(define (print-cake n)
(show " ∼a " n #\.)
(show " .-∼a-. " n #\|)
(show " | ∼a | " n #\space)
(show "---∼a---" n #\-))
(module* extras #f
(provide show))
In this revised "cake.rkt" module, show is not imported by a module that uses (require
"cake.rkt"), since most clients of "cake.rkt" will not want the extra function. A module
can require the extra submodule using (require (submod "cake.rkt" extras)) to
access the otherwise hidden show function. See submodule
paths for more
information on
submod.
6.2.4 Main and Test Submodules
The following variant of "cake.rkt" includes a main submodule that calls print-cake:
"cake.rkt"
#lang racket
(define (print-cake n)
(show " ∼a " n #\.)
(show " .-∼a-. " n #\|)
(show " | ∼a | " n #\space)
(show "---∼a---" n #\-))
(module* main #f
(print-cake 10))
121
Running a module does not run its module*-defined submodules. Nevertheless, running
the above module via racket or DrRacket prints a cake with 10 candles, because the main
submodule is a special case.
When a module is provided as a program name to the racket executable or run directly
within DrRacket, if the module has a main submodule, the main submodule is run after its
enclosing module. Declaring a main submodule thus specifies extra actions to be performed
when a module is run directly, instead of required as a library within a larger program.
A main submodule does not have to be declared with module*. If the main module does
not need to use bindings from its enclosing module, it can be declared with module. More
commonly, main is declared using module+:
(module+ name-id
decl ...)
A submodule declared with module+ is like one declared with module* using #f as its
initial-module-path . In addition, multiple module+ forms can specify the same sub-
module name, in which case the bodies of the module+ forms are combined to create a single
submodule.
The combining behavior of module+ is particularly useful for defining a test submodule,
which can be conveniently run using raco test in much the same way that main is con-
veniently run with racket. For example, the following "physics.rkt" module exports
drop and to-energy functions, and it defines a test module to hold unit tests:
"physics.rkt"
#lang racket
(module+ test
(require rackunit)
(define 1e-10))
(provide drop
to-energy)
(define (drop t)
(* 1/2 9.8 t t))
(module+ test
(check-= (drop 0) 0 )
(check-= (drop 10) 490 ))
(define (to-energy m)
(* m (expt 299792458.0 2)))
122
(module+ test
(check-= (to-energy 0) 0 )
(check-= (to-energy 1) 9e+16 1e+15))
Importing "physics.rkt" into a larger program does not run the drop and to-energy
tests—or even trigger the loading of the test code, if the module is compiled—but running
raco test physics.rkt at a command line runs the tests.
"physics.rkt"
#lang racket
(provide drop
to-energy)
(define (drop t)
(* 1/2 49/5 t t))
(define (to-energy m)
(* m (expt 299792458 2)))
(module* test #f
(require rackunit)
(define 1e-10)
(check-= (drop 0) 0 )
(check-= (drop 10) 490 )
(check-= (to-energy 0) 0 )
(check-= (to-energy 1) 9e+16 1e+15))
Using module+ instead of module* allows tests to be interleaved with function definitions.
The combining behavior of module+ is also sometimes helpful for a main module. Even
when combining is not needed, (module+ main ....) is preferred as more readable than
(module* main #f ....).
(quote id )
123
A module path that is a quoted identifier refers to a non-file module declaration
using the identifier. This form of module reference makes the most sense in a
REPL.
Examples:
rel-string
id
124
Another example of this form is racket, which is commonly used at the initial
import. The path racket is shorthand for racket/main; when an id has no /,
then /main is automatically added to the end. Thus, racket or racket/main
refers to the module whose source is the "main.rkt" file in the "racket"
collection.
Examples:
When the full path of a module ends with ".rkt", if no such file exists but
one does exist with the ".ss" suffix, then the ".ss" suffix is substituted au-
tomatically. This transformation provides compatibility with older versions of
Racket.
(lib rel-string )
125
(planet id )
Accesses a third-party library that is distributed through the PLaneT server. The
library is downloaded the first time that it is needed, and then the local copy is
used afterward.
The id encodes several pieces of information separated by a /: the package
owner, then package name with optional version information, and an optional
path to a specific library with the package. Like id as shorthand for a lib path,
a ".rkt" suffix is added automatically, and /main is used as the path if no
sub-path element is supplied.
Examples:
As with other forms, an implementation file ending with ".ss" can be substi-
tuted automatically if no implementation file ending with ".rkt" exists.
(planet package-string )
Like the symbol form of a planet, but using a string instead of an identifier.
Also, the package-string can end with a file suffix, in which case ".rkt" is
not added.
As with other forms, an ".ss" extension is converted to ".rkt", while an
implementation file ending with ".ss" can be substituted automatically if no
implementation file ending with ".rkt" exists.
vers = nat
| (nat nat )
| (= nat )
| (+ nat )
| (- nat )
126
A more general form to access a library from the PLaneT server. In this general
form, a PLaneT reference starts like a lib reference with a relative path, but the
path is followed by information about the producer, package, and version of the
library. The specified package is downloaded and installed on demand.
The vers es specify a constraint on the acceptable version of the package, where
a version number is a sequence of non-negative integers, and the constraints de-
termine the allowable values for each element in the sequence. If no constraint
is provided for a particular element, then any version is allowed; in particular,
omitting all vers es means that any version is acceptable. Specifying at least
one vers is strongly recommended.
For a version constraint, a plain nat is the same as (+ nat ), which matches
nat or higher for the corresponding element of the version number. A (start-
nat end-nat ) matches any number in the range start-nat to end-nat ,
inclusive. A (= nat ) matches only exactly nat . A (- nat ) matches nat or
lower.
Examples:
> (module m (lib "racket")
(require (planet "random.rkt" ("schematics" "random.plt" 1 0)))
(display (random-gaussian)))
The automatic ".ss" and ".rkt" conversions apply as with other forms.
(file string )
Refers to a file, where string is a relative or absolute path using the current
platform’s conventions. This form is not portable, and it should not be used
when a plain, portable rel-string suffices.
The automatic ".ss" and ".rkt" conversions apply as with other forms.
base = module-path
| "."
| ".."
element = id
| ".."
127
Examples:
> monkey
"Curious George"
Using "." as base within submod stands for the enclosing module. Using ".."
as base is equivalent to using "." followed by an extra "..". When a path of
the form (quote id ) refers to a submodule, it is equivalent to (submod "."
id ).
Using ".." as an element cancels one submodule step, effectively referring
to the enclosing module. For example, (submod "..") refers to the enclosing
module of the submodule in which the path appears.
Examples:
> dinner
"Curious George"
The require form imports from another module. A require form can appear within a
module, in which case it introduces bindings from the specified module into importing mod-
ule. A require form can also appear at the top level, in which case it both imports bindings
and instantiates the specified module; that is, it evaluates the body definitions and expres-
sions of the specified module, if they have not been evaluated already.
128
(require require-spec ...)
module-path
id-maybe-renamed = id
| [orig-id bind-id ]
129
> (module m (lib "racket")
(provide tastes-great?
less-filling?)
(define tastes-great? #t)
(define less-filling? #t))
> tastes-great?
#t
> less-filling?
less-filling?: undefined;
cannot reference undefined identifier
> (require (only-in 'm [less-filling? lite?]))
> lite?
#t
The only-in, except-in, rename-in, and prefix-in forms can be nested to implement
more complex manipulations of imported bindings. For example,
(require (prefix-in m: (except-in 'm ghost)))
imports all bindings that m exports, except for the ghost binding, and with local names that
are prefixed with m:.
Equivalently, the prefix-in could be applied before except-in, as long as the omission
with except-in is specified using the m: prefix:
(require (except-in (prefix-in m: 'm) m:ghost))
130
6.5 Exports: provide
By default, all of a module’s definitions are private to the module. The provide form
specifies definitions to be made available where the module is required.
A provide form can only appear at module level (i.e., in the immediate body of a module).
Specifying multiple provide-spec s in a single provide is exactly the same as using mul-
tiple provides each with a single provide-spec .
Each identifier can be exported at most once from a module across all provides within
the module. More precisely, the external name for each export must be distinct; the same
internal binding can be exported multiple times with different external names.
identifier
In its simplest form, a provide-spec indicates a binding within
its module to be exported. The binding can be from either a local
definition, or from an import.
(struct-out struct-id )
A struct-out form exports the bindings created by (struct
struct-id ....). See §5
“Programmer-
Defined Datatypes”
(all-defined-out) for information on
define-struct.
The all-defined-out shorthand exports all bindings that are de-
fined within the exporting module (as opposed to imported).
Use of the all-defined-out shorthand is generally discouraged,
because it makes less clear the actual exports for a module, and be-
cause Racket programmers get into the habit of thinking that defi-
nitions can be added freely to a module without affecting its public
interface (which is not the case when all-defined-out is used).
131
(all-from-out module-path )
The use of set! on variables defined within a module is limited to the body of the defining
module. That is, a module is allowed to change the value of its own definitions, and such
changes are visible to importing modules. However, an importing context is not allowed to
change the value of an imported binding.
Examples:
> counter
0
> (increment!)
132
> counter
1
> (set! counter -1)
set!: cannot mutate module-required identifier
in: counter
As the above example illustrates, a module can always grant others the ability to change its
exports by providing a mutator function, such as increment!.
The prohibition on assignment of imported variables helps support modular reasoning about
programs. For example, in the module,
(module m racket
(provide rx:fish fishy-string?)
(define rx:fish #rx"fish")
(define (fishy-string? s)
(regexp-match? s rx:fish)))
the function fishy-string? will always match strings that contain “fish”, no matter how
other modules use the rx:fish binding. For essentially the same reason that it helps pro-
grammers, the prohibition on assignment to imports also allows many programs to be exe-
cuted more efficiently.
Along the same lines, when a module contains no set! of a particular identifier that is de-
fined within the module, then the identifier is considered a constant that cannot be changed—
not even by re-declaring the module.
133
For exploration and debugging purposes, the Racket reflective layer provides a compile-
enforce-module-constants parameter to disable the enforcement of constants.
> pie
3
134
7 Contracts
Like a contract between two business partners, a software contract is an agreement between
two parties. The agreement specifies obligations and guarantees for each “product” (or
value) that is handed from one party to the other.
A contract thus establishes a boundary between the two parties. Whenever a value crosses
this boundary, the contract monitoring system performs contract checks, making sure the
partners abide by the established contract.
#lang racket
promises to all clients of the above module that the value of amount will always be a positive
number. The contract system monitors the module’s obligation carefully. Every time a client
refers to amount, the monitor checks that the value of amount is indeed a positive number.
The contracts library is built into the Racket language, but if you wish to use racket/base,
you can explicitly require the contracts library like this:
#lang racket/base
(require racket/contract) ; now we can write contracts
135
#lang racket
(define amount 0)
then, when the module is required, the monitoring system signals a violation of the contract
and blames the module for breaking its promises.
#lang racket
In this case, the monitoring system will apply positive? to a symbol, but positive?
reports an error, because its domain is only numbers. To make the contract capture our
intentions for all Racket values, we can ensure that the value is both a number and is positive,
combining the two contracts with and/c:
All of the contracts and modules in this chapter (excluding those just following) are writ-
ten using the standard #lang syntax for describing modules. Since modules serve as the
boundary between parties in a contract, examples involve multiple modules.
To experiment with multiple modules within a single module or within DrRacket’s defini-
tions area, use Racket’s submodules. For example, try the example earlier in this section like
this:
#lang racket
(module+ server
(provide (contract-out [amount (and/c number? positive?)]))
(define amount 150))
(module+ main
(require (submod ".." server))
(+ amount 10))
136
Each of the modules and their contracts are wrapped in parentheses with the module+ key-
word at the front. The first form after module is the name of the module to be used in a
subsequent require statement (where each reference through a require prefixes the name
with "..").
A mathematical function has a domain and a range. The domain indicates the kind of values
that the function can accept as arguments, and the range indicates the kind of values that it
produces. The conventional notation for a describing a function with its domain and range is
f : A -> B
Functions in a programming language have domains and ranges, too, and a contract can
ensure that a function receives only values in its domain and produces only values in its
range. A -> creates such a contract for a function. The forms after a -> specify contracts for
the domains and finally a contract for the range.
#lang racket
(provide (contract-out
[deposit (-> number? any)]
[balance (-> number?)]))
(define amount 0)
(define (deposit a) (set! amount (+ amount a)))
(define (balance) amount)
• deposit, which accepts a number and returns some value that is not specified in the
contract, and
• balance, which returns a number indicating the current balance of the account.
137
module. This client–server distinction is important, because when something goes wrong,
one or the other of the parties is to blame.
If a client module were to apply deposit to 'millions, it would violate the contract. The
contract-monitoring system would catch this violation and blame client for breaking the
contract with the above module. In contrast, if the balance function were to return 'broke,
the contract-monitoring system would blame the server module.
A -> by itself is not a contract; it is a contract combinator, which combines other contracts
to form a contract.
If you are used to mathematical function, you may prefer a contract arrow to appear between
the domain and the range of a function, not at the beginning. If you have read How to Design
Programs, you have seen this many times. Indeed, you may have seen contracts such as these
in other people’s code:
(provide (contract-out
[deposit (number? . -> . any)]))
If a Racket S-expression contains two dots with a symbol in the middle, the reader re-
arranges the S-expression and place the symbol at the front, as described in §2.4.3 “Lists
and Racket Syntax”. Thus,
(number? . -> . any)
The any contract used for deposit matches any kind of result, and it can only be used in the
range position of a function contract. Instead of any above, we could use the more specific
contract void?, which says that the function will always return the (void) value. The
void? contract, however, would require the contract monitoring system to check the return
value every time the function is called, even though the “client” module can’t do much with
the value. In contrast, any tells the monitoring system not to check the return value, it tells a
potential client that the “server” module makes no promises at all about the function’s return
value, even whether it is a single value or multiple values.
The any/c contract is similar to any, in that it makes no demands on a value. Unlike any,
any/c indicates a single value, and it is suitable for use as an argument contract. Using
138
any/c as a range contract imposes a check that the function produces a single value. That
is,
describes a function that accepts an integer and returns any number of values, while
describes a function that accepts an integer and produces a single result (but does not say
anything more about the result). The function
Use any/c as a result contract when it is particularly important to promise a single result
from a function. Use any when you want to promise as little as possible (and incur as little
checking as possible) for a function’s result.
The deposit function adds the given number to the value of amount. While the function’s
contract prevents clients from applying it to non-numbers, the contract still allows them
to apply the function to complex numbers, negative numbers, or inexact numbers, none of
which sensibly represent amounts of money.
The contract system allows programmers to define their own contracts as functions:
#lang racket
(define (amount? a)
(and (number? a) (integer? a) (exact? a) (>= a 0)))
(provide (contract-out
; an amount is a natural number of cents
; is the given number an amount?
[deposit (-> amount? any)]
[amount? (-> any/c boolean?)]
[balance (-> amount?)]))
(define amount 0)
(define (deposit a) (set! amount (+ amount a)))
(define (balance) amount)
139
This module defines an amount? function and uses it as a contract within -> contracts.
When a client calls the deposit function as exported with the contract (-> amount? any),
it must supply an exact, nonnegative integer, otherwise the amount? function applied to
the argument will return #f, which will cause the contract-monitoring system to blame the
client. Similarly, the server module must provide an exact, nonnegative integer as the result
of balance to remain blameless.
Of course, it makes no sense to restrict a channel of communication to values that the client
doesn’t understand. Therefore the module also exports the amount? predicate itself, with a
contract saying that it accepts an arbitrary value and returns a boolean.
In this case, we could also have used natural-number/c in place of amount?, since it
implies exactly the same check:
(provide (contract-out
[deposit (-> natural-number/c any)]
[balance (-> natural-number/c)]))
Every function that accepts one argument can be treated as a predicate and thus used as
a contract. For combining existing checks into a new one, however, contract combinators
such as and/c and or/c are often useful. For example, here is yet another way to write the
contracts above:
(define amount/c
(and/c number? integer? exact? (or/c positive? zero?)))
(provide (contract-out
[deposit (-> amount/c any)]
[balance (-> amount/c)]))
Other values also serve double duty as contracts. For example, if a function accepts a number
or #f, (or/c number? #f) suffices. Similarly, the amount/c contract could have been
written with a 0 in place of zero?. If you use a regular expression as a contract, the contract
accepts strings and byte strings that match the regular expression.
Naturally, you can mix your own contract-implementing functions with combinators like
and/c. Here is a module for creating strings from banking records:
#lang racket
(provide (contract-out
140
; convert a random number to a string
[format-number (-> number? string?)]
The contract of the exported function format-number specifies that the function consumes
a number and produces a string. The contract of the exported function format-nat is more
interesting than the one of format-number. It consumes only natural numbers. Its range
contract promises a string that has a . in the third position from the right.
If we want to strengthen the promise of the range contract for format-nat so that it admits
only strings with digits and a single dot, we could write it like this:
#lang racket
(define (digit-char? x)
(member x '(#\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\0)))
....
(provide (contract-out
....
; convert an amount (natural number) of cents
; into a dollar-based string
[format-nat (-> natural-number/c
(and/c string?
is-decimal-string?))]))
141
#lang racket
(provide
(contract-out
....
; convert an amount (natural number) of cents
; into a dollar-based string
[format-nat (-> natural-number/c
(and/c string? #rx"[0-9]*\\.[0-9][0-9]"))]))
Function contracts are not just restricted to having simple predicates on their domains or
ranges. Any of the contract combinators discussed here, including function contracts them-
selves, can be used as contracts on the arguments and results of a function.
For example,
is a contract that describes a curried function. It matches functions that accept one argument
and then return another function accepting a second argument before finally returning an
integer. If a server exports a function make-adder with this contract, and if make-adder
returns a value other than a function, then the server is to blame. If make-adder does return
a function, but the resulting function is applied to a value other than an integer, then the
client is to blame.
describes functions that accept other functions as its input. If a server exports a function
twice with this contract and the twice is applied to a value other than a function of one
argument, then the client is to blame. If twice is applied to a function of one argument and
twice calls the given function on a value other than an integer, then the server is to blame.
You wrote your module. You added contracts. You put them into the interface so that client
programmers have all the information from interfaces. It’s a piece of art:
142
(provide
(contract-out
[deposit (-> (λ (x)
(and (number? x) (integer? x) (>= x 0)))
any)]))
(define total 0)
(define (deposit a) (set! total (+ a total))))
Several clients used your module. Others used their modules in turn. And all of a sudden
one of them sees this error message:
What is the ??? doing there? Wouldn’t it be nice if we had a name for this class of data
much like we have string, number, and so on?
For this situation, Racket provides flat named contracts. The use of “contract” in this term
shows that contracts are first-class values. The “flat” means that the collection of data is a
subset of the built-in atomic classes of data; they are described by a predicate that consumes
all Racket values and produces a boolean. The “named” part says what we want to do, which
is to name the contract so that error messages become intelligible:
(define total 0)
(define (deposit a) (set! total (+ a total))))
With this little change, the error message becomes quite readable:
143
> (require 'improved-bank-server)
• a name for the function or method associated with the contract and either the phrase
“contract violation” or “violated it’s contract” depending on whether the contract was
violated by the server or the client; e.g. in the previous example:
deposit: contract violation
• a description of the precise aspect of the contract that was violated,
expected: amount
• the complete contract plus a path into it showing which aspect was violated,
given: -10
in: the 1st argument of
• the module where the contract was put (or, more generally, the boundary that the
contract mediates),
(-> amount any)
• who was blamed,
contract from: improved-bank-server
• and the source location where the contract appears.
blaming: top-level
The -> contract constructor works for functions that take a fixed number of arguments and
where the result contract is independent of the input arguments. To support other kinds of
functions, Racket supplies additional contract constructors, notably ->* and ->i.
144
7.3.1 Optional Arguments
Take a look at this excerpt from a string-processing module, inspired by the Scheme cook-
book:
#lang racket
(provide
(contract-out
; pad the given str left and right with
; the (optional) char so that it is centered
[string-pad-center (->* (string? natural-number/c)
(char?)
string?)]))
The module exports string-pad-center, a function that creates a string of a given width
with the given string in the center. The default fill character is #\space; if the client module
wishes to use a different character, it may call string-pad-center with a third argument,
a char, overwriting the default.
The function definition uses optional arguments, which is appropriate for this kind of func-
tionality. The interesting point here is the formulation of the contract for the string-pad-
center.
• The first one is a parenthesized group of contracts for all required arguments. In this
example, we see two: string? and natural-number/c.
• The second one is a parenthesized group of contracts for all optional arguments:
char?.
• The last one is a single contract: the result of the function.
Note if a default value does not satisfy a contract, you won’t get a contract error for this
interface. If you can’t trust yourself to get the initial value right, you need to communicate
the initial value across a boundary.
145
7.3.2 Rest Arguments
The max operator consumes at least one real number, but it accepts any number of additional
arguments. You can write other such functions using a “rest” argument, such as in max-abs: See §4.4.1
“Declaring a Rest
(define (max-abs n . rst) Argument” for an
introduction to rest
(foldr (lambda (n m) (max (abs n) m)) (abs n) rst)) arguments.
Describing this function through a contract requires a further extension of ->*: a #:rest
keyword specifies a contract on a list of arguments after the required and optional arguments:
(provide
(contract-out
[max-abs (->* (real?) () #:rest (listof real?) real?)]))
As always for ->*, the contracts for the required arguments are enclosed in the first pair
of parentheses, which in this case is a single real number. The empty pair of parenthesis
indicates that there are no optional arguments (not counting the rest arguments). The contract
for the rest argument follows #:rest; since all additional arguments must be real numbers,
the list of rest arguments must satisfy the contract (listof real?).
It turns out that the -> contract constructor also contains support for keyword arguments. For
example, consider this function, which creates a simple GUI and asks the user a yes-or-no
question: See §4.4.3
“Declaring
#lang racket/gui Keyword
Arguments” for an
introduction to
(define (ask-yes-or-no-question question keyword arguments.
#:default answer
#:title title
#:width w
#:height h)
(define d (new dialog% [label title] [width w] [height h]))
(define msg (new message% [label question] [parent d]))
(define (yes) (set! answer #t) (send d show #f))
(define (no) (set! answer #f) (send d show #f))
(define yes-b (new button%
[label "Yes"] [parent d]
[callback (λ (x y) (yes))]
[style (if answer '(border) '())]))
(define no-b (new button%
146
[label "No"] [parent d]
[callback (λ (x y) (no))]
[style (if answer '() '(border))]))
(send d show #t)
answer)
(provide (contract-out
[ask-yes-or-no-question
(-> string?
#:default boolean?
#:title string?
#:width exact-integer?
#:height exact-integer?
boolean?)]))
If you really want to
ask a yes-or-no
The contract for ask-yes-or-no-question uses ->, and in the same way that lambda (or question via a
GUI, you should use
define-based functions) allows a keyword to precede a functions formal argument, -> al- message-box/custom.
lows a keyword to precede a function contract’s argument contract. In this case, the contract For that matter, it’s
says that ask-yes-or-no-question must receive four keyword arguments, one for each usually better to
of the keywords #:default, #:title, #:width, and #:height. As in a function defini- provide buttons
with more specific
tion, the order of the keywords in -> relative to each other does not matter for clients of the answers than “yes”
function; only the relative order of argument contracts without keywords matters. and “no.”
To specify this function’s contract, we need to use ->* again. It supports keywords just as
you might expect in both the optional and mandatory argument sections. In this case, we
have the mandatory keyword #:default and optional keywords #:title, #:width, and
#:height. So, we write the contract like this:
(provide (contract-out
[ask-yes-or-no-question
(->* (string?
#:default boolean?)
147
(#:title string?
#:width exact-integer?
#:height exact-integer?)
boolean?)]))
That is, we put the mandatory keywords in the first section, and we put the optional ones in
the second section.
A function defined with case-lambda might impose different constraints on its arguments
depending on how many are provided. For example, a report-cost function might convert
either a pair of numbers or a string into a new string: See §4.4.4
“Arity-Sensitive
(define report-cost Functions:
case-lambda” for
(case-lambda an introduction to
[(lo hi) (format "between $∼a and $∼a" lo hi)] case-lambda.
[(desc) (format "∼a of dollars" desc)]))
> (report-cost 5 8)
"between $5 and $8"
> (report-cost "millions")
"millions of dollars"
The contract for such a function is formed with the case-> combinator, which combines as
many functional contracts as needed:
(provide (contract-out
[report-cost
(case->
(integer? integer? . -> . string?)
(string? . -> . string?))]))
As you can see, the contract for report-cost combines two function contracts, which is
just as many clauses as the explanation of its functionality required.
148
(provide
(contract-out
[real-sqrt (->i ([argument (>=/c 1)])
[result (argument) (<=/c argument)])]))
The word “indy” is
meant to suggest
The contract for the exported function real-sqrt uses the ->i rather than ->* function that blame may be
contract. The “i” stands for an indy dependent contract, meaning the contract for the function assigned to the
contract itself,
range depends on the value of the argument. The appearance of argument in the line for because the contract
result’s contract means that the result depends on the argument. In this particular case, the must be considered
argument of real-sqrt is greater or equal to 1, so a very basic correctness check is that the an independent
result is smaller than the argument. component. The
name was chosen in
response to two
In general, a dependent function contract looks just like the more general ->* contract, but existing
with names added that can be used elsewhere in the contract. labels—“lax” and
“picky”—for
Going back to the bank-account example, suppose that we generalize the module to support different semantics
of function
multiple accounts and that we also include a withdrawal operation. The improved bank- contracts in the
account module includes an account structure type and the following functions: research literature.
(provide (contract-out
[balance (-> account? amount/c)]
[withdraw (-> account? amount/c account?)]
[deposit (-> account? amount/c account?)]))
Besides requiring that a client provide a valid amount for a withdrawal, however, the amount
should be less than or equal to the specified account’s balance, and the resulting account will
have less money than it started with. Similarly, the module might promise that a deposit pro-
duces an account with money added to the account. The following implementation enforces
those constraints and guarantees through contracts:
#lang racket
149
(>= (balance res)
(- (balance acc) amt))))])]
[deposit (->i ([acc account?]
[amt amount/c])
[result (acc amt)
(and/c account?
(lambda (res)
(>= (balance res)
(+ (balance acc) amt))))])]))
The contracts in section 2 provide typical type-like guarantees for create and balance. For
withdraw and deposit, however, the contracts check and guarantee the more complicated
constraints on balance and deposit. The contract on the second argument to withdraw
uses (balance acc) to check whether the supplied withdrawal amount is small enough,
where acc is the name given within ->i to the function’s first argument. The contract on
the result of withdraw uses both acc and amt to guarantee that no more than that requested
amount was withdrawn. The contract on deposit similarly uses acc and amount in the
result contract to guarantee that at least as much money as provided was deposited into the
account.
As written above, when a contract check fails, the error message is not great. The following
revision uses flat-named-contract within a helper function mk-account-contract to
provide better error messages.
#lang racket
150
(define (ctr a)
(and (account? a) (op balance0 (balance a))))
(flat-named-contract (format msg balance0) ctr))
The ->i contract combinator can also ensure that a function only modifies state according
to certain constraints. For example, consider this contract (it is a slightly simplified from the
function preferences:add-panel in the framework):
It says that the function accepts a single argument, named parent, and that parent must be
151
an object matching the interface area-container-window<%>.
The range contract ensures that the function only modifies the children of parent by adding
a new child to the front of the list. It accomplishes this by using the _ instead of a normal
identifier, which tells the contract library that the range contract does not depend on the
values of any of the results, and thus the contract library evaluates the expression follow-
ing the _ when the function is called, instead of when it returns. Therefore the call to the
get-children method happens before the function under the contract is called. When the
function under contract returns, its result is passed in as child, and the contract ensures that
the children after the function return are the same as the children before the function called,
but with one more child, at the front of the list.
To see the difference in a toy example that focuses on this point, consider this program
#lang racket
(define x '())
(define (get-x) x)
(define (f) (set! x (cons 'f x)))
(provide
(contract-out
[f (->i () [_ (begin (set! x (cons 'ctc x)) any/c)])]
[get-x (-> (listof symbol?))]))
If you were to require this module, call f, then the result of get-x would be '(f ctc). In
contrast, if the contract for f were
(only changing the underscore to res), then the result of get-x would be '(ctc f).
The function split consumes a list of chars and delivers the string that occurs before the
first occurrence of #\newline (if any) and the rest of the list:
(define (split l)
(define (split l w)
(cond
[(null? l) (values (list->string (reverse w)) '())]
[(char=? #\newline (car l))
(values (list->string (reverse w)) (cdr l))]
[else (split (cdr l) (cons (car l) w))]))
(split l '()))
152
It is a typical multiple-value function, returning two values by traversing a single list.
The contract for such a function can use the ordinary function arrow ->, since -> treats
values specially when it appears as the last result:
(provide (contract-out
[split (-> (listof char?)
(values string? (listof char?)))]))
The contract for such a function can also be written using ->*:
(provide (contract-out
[split (->* ((listof char?))
()
(values string? (listof char?)))]))
As before, the contract for the argument with ->* is wrapped in an extra pair of parentheses
(and must always be wrapped like that) and the empty pair of parentheses indicates that there
are no optional arguments. The contracts for the results are inside values: a string and a
list of characters.
Now, suppose that we also want to ensure that the first result of split is a prefix of the given
word in list format. In that case, we need to use the ->i contract combinator:
(define (substring-of? s)
(flat-named-contract
(format "substring of ∼s" s)
(lambda (s2)
(and (string? s2)
(<= (string-length s2) (string-length s))
(equal? (substring s 0 (string-length s2)) s2)))))
(provide
(contract-out
[split (->i ([fl (listof char?)])
(values [s (fl) (substring-of? (list->string fl))]
[c (listof char?)]))]))
Like ->*, the ->i combinator uses a function over the argument to create the range contracts.
Yes, it doesn’t just return one contract but as many as the function produces values: one
contract per value. In this case, the second contract is the same as before, ensuring that the
second result is a list of chars. In contrast, the first contract strengthens the old one so that
the result is a prefix of the given word.
153
This contract is expensive to check, of course. Here is a slightly cheaper version:
(provide
(contract-out
[split (->i ([fl (listof char?)])
(values [s (fl) (string-len/c (length fl))]
[c (listof char?)]))]))
Imagine yourself writing a contract for a function that accepts some other function and a
list of numbers that eventually applies the former to the latter. Unless the arity of the given
function matches the length of the given list, your procedure is in trouble.
The argument of n-step is proc, a function proc whose results are either numbers or false,
and a list. It then applies proc to the list inits. As long as proc returns a number, n-step
treats that number as an increment for each of the numbers in inits and recurs. When proc
returns false, the loop stops.
154
A contract for n-step must specify two aspects of proc’s behavior: its arity must include
the number of elements in inits, and it must return either a number or #f. The latter is
easy, the former is difficult. At first glance, this appears to suggest a contract that assigns a
variable-arity to proc:
(->* ()
(listof any/c)
(or/c number? false/c))
This contract, however, says that the function must accept any number of arguments, not a
specific but undetermined number. Thus, applying n-step to (lambda (x) x) and (list
1) breaks the contract because the given function accepts only one argument.
The correct contract uses the unconstrained-domain-> combinator, which specifies only
the range of a function, not its domain. It is then possible to combine this contract with an
arity test to specify the correct n-step’s contract:
(provide
(contract-out
[n-step
(->i ([proc (inits)
(and/c (unconstrained-domain->
(or/c false/c number?))
(λ (f) (procedure-arity-includes?
f
(length inits))))]
[inits (listof number?)])
()
any)]))
This section develops several different flavors of contracts for one and the same example:
Racket’s argmax function. According to its Racket documentation, the function consumes
a procedure proc and a non-empty list of values, lst. It
returns the first element in the list lst that maximizes the result of proc.
Examples:
155
> (argmax add1 (list 1 2 3))
3
> (argmax sqrt (list 0.4 0.9 0.16))
0.9
> (argmax second '((a 2) (b 3) (c 4) (d 1) (e 4)))
'(c 4)
version 1
#lang racket
(provide
(contract-out
[argmax (-> (-> any/c real?) (and/c pair? list?) any/c)]))
This contract captures two essential conditions of the informal description of argmax:
• the given function must produce numbers that are comparable according to <. In
particular, the contract (-> any/c number?) would not do, because number? also
recognizes complex numbers in Racket.
• the given list must contain at least one item.
When combined with the name, the contract explains the behavior of argmax at the same
level as an ML function type in a module signature (except for the non-empty list aspect).
Contracts may communicate significantly more than a type signature, however. Take a look
at this second contract for argmax:
version 2
#lang racket
(provide
(contract-out
[argmax
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
156
(define f@r (f r))
(for/and ([v lov]) (>= f@r (f v))))))]))
It is a dependent contract that names the two arguments and uses the names to impose a
predicate on the result. This predicate computes (f r) – where r is the result of argmax –
and then validates that this value is greater than or equal to all values of f on the items of
lov.
Is it possible that argmax could cheat by returning a random value that accidentally maxi-
mizes f over all elements of lov? With a contract, it is possible to rule out this possibility:
version 2 rev. a
#lang racket
(provide
(contract-out
[argmax
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
(define f@r (f r))
(and (memq r lov)
(for/and ([v lov]) (>= f@r (f v)))))))]))
The memq function ensures that r is intensionally equal to one of the members of lov. Of That is, "pointer
course, a moment’s worth of reflection shows that it is impossible to make up such a value. equality" for those
who prefer to think
Functions are opaque values in Racket and without applying a function, it is impossible at the hardware
to determine whether some random input value produces an output value or triggers some level.
exception. So we ignore this possibility from here on.
Version 2 formulates the overall sentiment of argmax’s documentation, but it fails to bring
across that the result is the first element of the given list that maximizes the given function
f. Here is a version that communicates this second aspect of the informal documentation:
version 3
#lang racket
(provide
(contract-out
[argmax
157
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
(define f@r (f r))
(and (for/and ([v lov]) (>= f@r (f v)))
(eq? (first (memf (lambda (v) (= (f v) f@r)) lov))
r)))))]))
That is, the memf function determines the first element of lov whose value under f is equal
to r’s value under f. If this element is intensionally equal to r, the result of argmax is
correct.
This second refinement step introduces two problems. First, both conditions recompute
the values of f for all elements of lov. Second, the contract is now quite difficult to read.
Contracts should have a concise formulation that a client can comprehend with a simple scan.
Let us eliminate the readability problem with two auxiliary functions that have reasonably
meaningful names:
version 3 rev. a
#lang racket
(provide
(contract-out
[argmax
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
(define f@r (f r))
(and (is-first-max? r f@r f lov)
(dominates-all f@r f lov)))))]))
; where
The names of the two predicates express their functionality and, in principle, render it un-
necessary to read their definitions.
158
This step leaves us with the problem of the newly introduced inefficiency. To avoid the
recomputation of (f v) for all v on lov, we change the contract so that it computes these
values and reuses them as needed:
version 3 rev. b
#lang racket
(provide
(contract-out
[argmax
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
(define f@r (f r))
(define flov (map f lov))
(and (is-first-max? r f@r (map list lov flov))
(dominates-all f@r flov)))))]))
; where
Now the predicate on the result once again computes all values of f for elements of lov
once. The word "eager"
comes from the
Version 3 may still be too eager when it comes to calling f. While Racket’s argmax always literature on the
linguistics of
calls f no matter how many items lov contains, let us imagine for illustrative purposes that contracts.
our own implementation first checks whether the list is a singleton. If so, the first element
would be the only element of lov and in that case there would be no need to compute (f
r). As a matter of fact, since f may diverge or raise an exception for some inputs, argmax The argmax of
should avoid calling f when possible. Racket implicitly
argues that it not
only promises the
The following contract demonstrates how a higher-order dependent contract needs to be first value that
adjusted so as to avoid being over-eager: maximizes f over
lov but also that f
produces/produced
159 a value for the
result.
version 4
#lang racket
(provide
(contract-out
[argmax
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
(r (f lov)
(lambda (r)
(cond
[(empty? (rest lov)) (eq? (first lov) r)]
[else
(define f@r (f r))
(define flov (map f lov))
(and (is-first-max? r f@r (map list lov flov))
(dominates-all f@r flov))]))))]))
; where
Note that such considerations don’t apply to the world of first-order contracts. Only a higher-
order (or lazy) language forces the programmer to express contracts with such precision.
The problem of diverging or exception-raising functions should alert the reader to the even
more general problem of functions with side-effects. If the given function f has visible
effects – say it logs its calls to a file – then the clients of argmax will be able to observe
two sets of logs for each call to argmax. To be precise, if the list of values contains more
than one element, the log will contain two calls of f per value on lov. If f is expensive to
compute, doubling the calls imposes a high cost.
To avoid this cost and to signal problems with overly eager contracts, a contract system could
record the i/o of contracted function arguments and use these hashtables in the dependency
specification. This is a topic of on-going research in PLT. Stay tuned.
160
7.5 Contracts on Structures
Modules deal with structures in two ways. First they export struct definitions, i.e., the
ability to create structs of a certain kind, to access their fields, to modify them, and to distin-
guish structs of this kind against every other kind of value in the world. Second, on occasion
a module exports a specific struct and wishes to promise that its fields contain values of a
certain kind. This section explains how to protect structs with contracts for both uses.
If your module defines a variable to be a structure, then you can specify the structure’s shape
using struct/c:
#lang racket
(require lang/posn)
(provide (contract-out
[origin (struct/c posn zero? zero?)]))
In this example, the module imports a library for representing positions, which exports a
posn structure. One of the posns it creates and exports stands for the origin, i.e., (0,0), of
the grid. See also vector/c
and similar contract
combinators for
(flat) compound
7.5.2 Guarantees for All Values data.
The book How to Design Programs teaches that posns should contain only numbers in their
two fields. With contracts we would enforce this informal data definition as follows:
#lang racket
(struct posn (x y))
(provide (contract-out
[struct posn ((x number?) (y number?))]
[p-okay posn?]
[p-sick posn?]))
This module exports the entire structure definition: posn, posn?, posn-x, posn-y, set-
posn-x!, and set-posn-y!. Each function enforces or promises that the two fields of a
161
posn structure are numbers — when the values flow across the module boundary. Thus, if a
client calls posn on 10 and 'a, the contract system signals a contract violation.
The creation of p-sick inside of the posn module, however, does not violate the contracts.
The function posn is used internally, so 'a and 'b don’t cross the module boundary. Simi-
larly, when p-sick crosses the boundary of posn, the contract promises a posn? and noth-
ing else. In particular, this check does not require that the fields of p-sick are numbers.
The association of contract checking with module boundaries implies that p-okay and p-
sick look alike from a client’s perspective until the client extracts the pieces:
#lang racket
(require lang/posn)
Using posn-x is the only way the client can find out what a posn contains in the x field. The
application of posn-x sends p-sick back into the posn module and the result value – 'a
here – back to the client, again across the module boundary. At this very point, the contract
system discovers that a promise is broken. Specifically, posn-x doesn’t return a number but
a symbol and is therefore blamed.
This specific example shows that the explanation for a contract violation doesn’t always
pinpoint the source of the error. The good news is that the error is located in the posn
module. The bad news is that the explanation is misleading. Although it is true that posn-x
produced a symbol instead of a number, it is the fault of the programmer who created a posn
from symbols, i.e., the programmer who added
to the module. So, when you are looking for bugs based on contract violations, keep this
example in mind.
If we want to fix the contract for p-sick so that the error is caught when sick is exported,
a single change suffices:
(provide
(contract-out
...
[p-sick (struct/c posn number? number?)]))
That is, instead of exporting p-sick as a plain posn?, we use a struct/c contract to
enforce constraints on its components.
162
7.5.3 Checking Properties of Data Structures
Contracts written using struct/c immediately check the fields of the data structure, but
sometimes this can have disastrous effects on the performance of a program that does not,
itself, inspect the entire data structure.
As an example, consider the binary search tree search algorithm. A binary search tree is like
a binary tree, except that the numbers are organized in the tree to make searching the tree
fast. In particular, for each interior node in the tree, all of the numbers in the left subtree are
smaller than the number in the node, and all of the numbers in the right subtree are larger
than the number in the node.
We can implement a search function in? that takes advantage of the structure of the binary
search tree.
#lang racket
163
In a full binary search tree, this means that the in? function only has to explore a logarithmic
number of nodes.
The contract on in? guarantees that its input is a binary search tree. But a little careful
thought reveals that this contract defeats the purpose of the binary search tree algorithm. In
particular, consider the inner cond in the in? function. This is where the in? function gets
its speed: it avoids searching an entire subtree at each recursive call. Now compare that
to the bst-between? function. In the case that it returns #t, it traverses the entire tree,
meaning that the speedup of in? is lost.
In order to fix that, we can employ a new strategy for checking the binary search tree contract.
In particular, if we only checked the contract on the nodes that in? looks at, we can still
guarantee that the tree is at least partially well-formed, but without changing the complexity.
The node/c function accepts a contract for each field of the struct and returns a contract
on the struct. More interestingly, the syntactic form node/dc allows us to write dependent
contracts, i.e., contracts where some of the contracts on the fields depend on the values of
other fields. We can use this to define the binary search tree contract:
#lang racket
164
In general, each use of node/dc must name the fields and then specify contracts for each
field. In the above, the val field is a contract that accepts values between low and high.
The left and right fields are dependent on the value of the val field, indicated by their
second sub-expressions. Their contracts are built by recursive calls to the bst-between/c
function. Taken together, this contract ensures the same thing that the bst-between? func-
tion checked in the original example, but here the checking only happens as in? explores
the tree.
Although this contract improves the performance of in?, restoring it to the logarithmic be-
havior that the contract-less version had, it is still imposes a fairly large constant overhead.
So, the contract library also provides define-opt/c that brings down that constant factor
by optimizing its body. Its shape is just like the define above. It expects its body to be a
contract and then optimizes that contract.
The contract system provides existential contracts that can protect abstractions, ensuring
that clients of your module cannot depend on the precise representation choices you make
for your data structures. You can type
#:exists instead
The contract-out form allows you to write of #:∃ if you
cannot easily type
unicode characters;
in DrRacket, typing
#:∃ name-of-a-new-contract \exists followed
by either alt-\ or
control-\
as one of its clauses. This declaration introduces the variable name-of-a-new-contract , (depending on your
binding it to a new contract that hides information about the values it protects. platform) will
produce ∃.
As an example, consider this (simple) implementation of a queue datastructure:
#lang racket
(define empty '())
(define (enq top queue) (append queue (list top)))
(define (next queue) (car queue))
(define (deq queue) (cdr queue))
(define (empty? queue) (null? queue))
(provide
165
(contract-out
[empty (listof integer?)]
[enq (-> integer? (listof integer?) (listof integer?))]
[next (-> (listof integer?) integer?)]
[deq (-> (listof integer?) (listof integer?))]
[empty? (-> (listof integer?) boolean?)]))
This code implements a queue purely in terms of lists, meaning that clients of this data
structure might use car and cdr directly on the data structure (perhaps accidentally) and
thus any change in the representation (say to a more efficient representation that supports
amortized constant time enqueue and dequeue operations) might break client code.
To ensure that the queue representation is abstract, we can use #:∃ in the contract-out
expression, like this:
(provide
(contract-out
#:∃ queue
[empty queue]
[enq (-> integer? queue queue)]
[next (-> queue integer?)]
[deq (-> queue (listof integer?))]
[empty? (-> queue boolean?)]))
Now, if clients of the data structure try to use car and cdr, they receive an error, rather than
mucking about with the internals of the queues.
This section illustrates the current state of Racket’s contract implementation with a series of
examples from Design by Contract, by Example [Mitchell02].
Mitchell and McKim’s principles for design by contract DbC are derived from the 1970s
style algebraic specifications. The overall goal of DbC is to specify the constructors of an
algebra in terms of its observers. While we reformulate Mitchell and McKim’s terminology
and we use a mostly applicative approach, we retain their terminology of “classes” and
“objects”:
166
In applicative implementation a command typically returns an new object of the same
class.
• Separate basic queries from derived queries.
A derived query returns a result that is computable in terms of basic queries.
• For each derived query, write a post-condition contract that specifies the result
in terms of the basic queries.
• For each command, write a post-condition contract that specifies the changes to
the observable properties in terms of the basic queries.
Each of the following sections corresponds to a chapter in Mitchell and McKim’s book (but
not all chapters show up here). We recommend that you read the contracts first (near the end
of the first modules), then the implementation (in the first modules), and then the test module
(at the end of each section).
Mitchell and McKim use Eiffel as the underlying programming language and employ a con-
ventional imperative programming style. Our long-term goal is to transliterate their exam-
ples into applicative Racket, structure-oriented imperative Racket, and Racket’s class sys-
tem.
Note: To mimic Mitchell and McKim’s informal notion of parametericity (parametric poly-
morphism), we use first-class contracts. At several places, this use of first-class contracts
improves on Mitchell and McKim’s design (see comments in interfaces).
This first module contains some struct definitions in a separate module in order to better
track bugs.
#lang racket
; data definitions
; interface
(provide
(contract-out
[id? (-> any/c boolean?)]
[id-equal? (-> id? id? boolean?)]
167
[struct basic-customer ((id id?)
(name string?)
(address string?))]))
; end of interface
; implementation
; [listof (list basic-customer? secret-info)]
(define all '())
(define (find c)
(define (has-c-as-key p)
(id-equal? (basic-customer-id (car p)) c))
(define x (filter has-c-as-key all))
(if (pair? x) (car x) x))
(define (active? c)
(pair? (find c)))
(define count 0)
(define (add c)
(set! all (cons (list c 'secret) all))
(set! count (+ count 1)))
(define c0 0)
; end of implementation
(provide
(contract-out
; how many customers are in the db?
168
[count natural-number/c]
; is the customer with this id active?
[active? (-> id? boolean?)]
; what is the name of the customer with this id?
[name (-> (and/c id? active?) string?)]
; change the name of the customer with this id
[set-name (->d ([id id?] [nn string?])
()
[result any/c] ; result contract
#:post-cond
(string=? (name id) nn))]
The tests:
#lang racket
(require rackunit rackunit/text-ui "1.rkt" "1b.rkt")
(run-tests
(test-suite
"manager"
(test-equal? "id lookup" "matthias" (name 'mf))
(test-equal? "count" 4 count)
(test-true "active?" (active? 'mf))
(test-false "active? 2" (active? 'kk))
(test-true "set name" (void? (set-name 'mf "matt")))))
#lang racket
169
; a contract utility
(define (eq/c x) (lambda (y) (eq? x y)))
(provide
(contract-out
; predicate
[stack? (-> any/c boolean?)]
; primitive queries
; how many items are on the stack?
[count (-> stack? natural-number/c)]
; derived queries
; is the stack empty?
[is-empty?
(->d ([s stack?])
()
[result (eq/c (= (count s) 0))])]
170
; creation
[initialize
(->d ([p contract?] [s (p p . -> . boolean?)])
()
; Mitchell and McKim use (= (count s) 0) here to express
; the post-condition in terms of a primitive query
[result (and/c stack? is-empty?)])]
; commands
; add an item to the top of the stack
[push
(->d ([s stack?] [x (stack-p? s)])
()
[sn stack?] ; result kind
#:post-cond
(and (= (+ (count s) 1) (count sn))
([stack-eq s] x (top sn))))]
The tests:
#lang racket
(require rackunit rackunit/text-ui "2.rkt")
(run-tests
(test-suite
"stack"
(test-true
"empty"
(is-empty? (initialize (flat-contract integer?) =)))
(test-true "push" (stack? s2))
(test-true
"push exn"
(with-handlers ([exn:fail:contract? (lambda _ #t)])
(push (initialize (flat-contract integer?)) 'a)
171
#f))
(test-true "pop" (stack? (pop s2)))
(test-equal? "top" (top s2) 1)
(test-equal? "toppop" (top (pop s2)) 2)))
7.7.3 A Dictionary
#lang racket
; implementation
(define-struct dictionary (l value? eq?))
; the keys should probably be another parameter (exercise)
; interface
(provide
(contract-out
; predicates
[dictionary? (-> any/c boolean?)]
; basic queries
172
; how many items are in the dictionary?
[count (-> dictionary? natural-number/c)]
; does the dictionary define key k?
[has? (->d ([d dictionary?] [k symbol?])
()
[result boolean?]
#:post-cond
((zero? (count d)) . ⇒ . (not result)))]
; what is the value of key k in this dictionary?
[value-for (->d ([d dictionary?]
[k (and/c symbol? (lambda (k) (has? d k)))])
()
[result (dictionary-value? d)])]
; initialization
; post condition: for all k in symbol, (has? d k) is false.
[initialize (->d ([p contract?] [eq (p p . -> . boolean?)])
()
[result (and/c dictionary? (compose zero? count))])]
; commands
; Mitchell and McKim say that put shouldn't consume Void (null
ptr)
; for v. We allow the client to specify a contract for all val-
ues
; via initialize. We could do the same via a key? parameter
; (exercise). add key k with value v to this dictionary
[put (->d ([d dictionary?]
[k (and symbol? (not-has? d))]
[v (dictionary-value? d)])
()
[result dictionary?]
#:post-cond
(and (has? result k)
(= (count d) (- (count result) 1))
([dictionary-eq? d] (value-
for result k) v)))]
; remove key k from this dictionary
[rem (->d ([d dictionary?]
[k (and/c symbol? (lambda (k) (has? d k)))])
()
[result (and/c dictionary? not-has?)]
#:post-cond
(= (count d) (+ (count result) 1)))]))
; end of interface
The tests:
173
#lang racket
(require rackunit rackunit/text-ui "3.rkt")
(run-tests
(test-suite
"dictionaries"
(test-equal? "value for" 2 (value-for d 'b))
(test-false "has?" (has? (rem d 'b) 'b))
(test-equal? "count" 3 (count d))))
7.7.4 A Queue
#lang racket
; a contract utility
(define (all-but-last l) (reverse (cdr (reverse l))))
(define (eq/c x) (lambda (y) (eq? x y)))
; implementation
(define-struct queue (list p? eq))
; interface
(provide
174
(contract-out
; predicate
[queue? (-> any/c boolean?)]
; primitive queries
; Imagine providing this 'query' for the interface of the module
; only. Then in Racket there is no reason to have count or is-
empty?
; around (other than providing it to clients). After all items
is
; exactly as cheap as count.
[items (->d ([q queue?]) () [result (listof (queue-
p? q))])]
; derived queries
[count (->d ([q queue?])
; We could express this second part of the post
; condition even if count were a module "at-
tribute"
; in the language of Eiffel; indeed it would
use the
; exact same syntax (minus the arrow and
domain).
()
[result (and/c natural-number/c
(=/c (length (items q))))])]
; commands
[put (->d ([oldq queue?] [i (queue-p? oldq)])
()
[result
(and/c
175
queue?
(lambda (q)
(define old-items (items oldq))
(equal? (items q) (append old-
items (list i)))))])]
The tests:
#lang racket
(require rackunit rackunit/text-ui "5.rkt")
(run-tests
(test-suite
"queue"
(test-true
"empty"
(is-empty? (initialize (flat-contract integer?) =)))
(test-true "put" (queue? s))
(test-equal? "count" 2 (count s))
(test-true "put exn"
(with-handlers ([exn:fail:contract? (lambda _ #t)])
(put (initialize (flat-contract integer?)) 'a)
#f))
(test-true "remove" (queue? (rem s)))
(test-equal? "head" 2 (head s))))
7.8 Gotchas
As a general rule, adding a contract to a program should either leave the behavior of the
program unchanged, or should signal a contract violation. And this is almost true for Racket
contracts, with one exception: eq?.
176
The eq? procedure is designed to be fast and does not provide much in the way of guarantees,
except that if it returns true, it means that the two values behave identically in all respects.
Internally, this is implemented as pointer equality at a low-level so it exposes information
about how Racket is implemented (and how contracts are implemented).
Contracts interact poorly with eq? because function contract checking is implemented inter-
nally as wrapper functions. For example, consider this module:
#lang racket
(define (make-adder x)
(if (= 1 x)
add1
(lambda (y) (+ x y))))
(provide (contract-out
[make-adder (-> number? (-> number? number?))]))
It exports the make-adder function that is the usual curried addition function, except that it
returns Racket’s add1 when its input is 1.
(eq? (make-adder 1)
(make-adder 1))
would return #t, but it does not. If the contract were changed to any/c (or even (->
number? any/c)), then the eq? call would return #t.
Much like the eq? example above, #:∃ contracts can change the behavior of a program.
Specifically, the null? predicate (and many other predicates) return #f for #:∃ contracts,
and changing one of those contracts to any/c means that null? might now return #t instead,
resulting in arbitrarily different behavior depending on how this boolean might flow around
in the program.
#lang racket/exists
To work around the above problem, the racket/exists library behaves just like racket,
but predicates signal errors when given #:∃ contracts.
177
Moral: Do not use predicates on #:∃ contracts, but if you’re not sure, use racket/exists
to be safe.
When defining a self-referential contract, it is natural to use define. For example, one might
try to write a contract on streams like this:
> (define stream/c
(promise/c
(or/c null?
(cons/c number? stream/c))))
stream/c: undefined;
cannot reference undefined identifier
Unfortunately, this does not work because the value of stream/c is needed before it is
defined. Put another way, all of the combinators evaluate their arguments eagerly, even
though the values that they accept do not.
Instead, use
(define stream/c
(promise/c
(or/c
null?
(cons/c number? (recursive-contract stream/c)))))
The use of recursive-contract delays the evaluation of the identifier stream/c until
after the contract is first checked, long enough to ensure that stream/c is defined.
The contract library assumes that variables exported via contract-out are not assigned
to, but does not enforce it. Accordingly, if you try to set! those variables, you may be
surprised. Consider the following example:
> (module server racket
(define (inc-x!) (set! x (+ x 1)))
(define x 0)
(provide (contract-out [inc-x! (-> void?)]
[x integer?])))
178
> (module client racket
(require 'server)
(print-latest)
(inc-x!)
(print-latest))
Both calls to print-latest print 0, even though the value of x has been incremented (and
the change is visible inside the module x).
To work around this, export accessor functions, rather than exporting the variable directly,
like this:
#lang racket
(define (get-x) x)
(define (inc-x!) (set! x (+ x 1)))
(define x 0)
(provide (contract-out [inc-x! (-> void?)]
[get-x (-> integer?)]))
179
8 Input and Output
A Racket port represents an input or output stream, such as a file, a terminal, a TCP con-
nection, or an in-memory string. More specifically, an input port represents a stream from
which a program can read data, and an output port represents a stream for writing data.
Various functions create various kinds of ports. Here are a few examples:
• Files: The open-output-file function opens a file for writing, and open-input-
file opens a file for reading.
Examples:
180
> (call-with-output-file "data"
#:exists 'truncate
(lambda (out)
(display "hello" out)))
> (get-output-string p)
"hello"
> (read-line (open-input-string "goodbye\nfarewell"))
"goodbye"
• TCP Connections: The tcp-connect function creates both an input port and an
output port for the client side of a TCP communication. The tcp-listen function
creates a server, which accepts connections via tcp-accept.
Examples:
• Process Pipes: The subprocess function runs a new process at the OS level and re-
turns ports that correspond to the subprocess’s stdin, stdout, and stderr. (The first three
181
arguments can be certain kinds of existing ports to connect directly to the subprocess,
instead of creating new ports.)
Examples:
• Internal Pipes: The make-pipe function returns two ports that are ends of a pipe.
This kind of pipe is internal to Racket, and not related to OS-level pipes for commu-
nicating between different processes.
Examples:
For most simple I/O functions, the target port is an optional argument, and the default is
the current input port or current output port. Furthermore, error messages are written to the
current error port, which is an output port. The current-input-port, current-output-
port, and current-error-port functions return the corresponding current ports.
Examples:
182
> (display "Hi" (current-output-port)) ; the same
Hi
If you start the racket program in a terminal, then the current input, output, and error ports
are all connected to the terminal. More generally, they are connected to the OS-level stdin,
stdout, and stderr. In this guide, the examples show output written to stdout in purple, and
output written to stderr in red italics.
Examples:
(define (swing-hammer)
(display "Ouch!" (current-error-port)))
> (swing-hammer)
Ouch!
The current-port functions are actually parameters, which means that their values can be set
with parameterize. See §4.13
“Dynamic Binding:
Example: parameterize”
for an introduction
to parameters.
> (let ([s (open-output-string)])
(parameterize ([current-error-port s])
(swing-hammer)
(swing-hammer)
(swing-hammer))
(get-output-string s))
"Ouch!Ouch!Ouch!"
As noted throughout §3 “Built-In Datatypes”, Racket provides three ways to print an instance
of a built-in value:
• print, which prints a value in the same way that is it printed for a REPL result; and
• write, which prints a value in such a way that read on the output produces the value
back; and
• display, which tends to reduce a value to just its character or byte content—at least
for those datatypes that are primarily about characters or bytes, otherwise it falls back
to the same output as write.
183
Here are some examples using each:
> (print '|pea pod|) > (write '|pea pod|) > (display '|pea pod|)
'|pea pod| |pea pod| pea pod
> (print '("i" pod)) > (write '("i" pod)) > (display '("i" pod))
'("i" pod) ("i" pod) (i pod)
Overall, print corresponds to the expression layer of Racket syntax, write corresponds to
the reader layer, and display roughly corresponds to the character layer.
The printf function supports simple formatting of data and text. In the format string sup-
plied to printf, ∼a displays the next argument, ∼s writes the next argument, and ∼v
prints the next argument.
Examples:
After using write, as opposed to display or print, many forms of data can be read back
in using read. The same values printed can also be parsed by read, but the result may
have extra quote forms, since a printed form is meant to be read like an expression.
Examples:
184
> (write "hello" out)
Prefab structure types (see §5.7 “Prefab Structure Types”) automatically support serializa-
tion: they can be written to an output stream, and a copy can be read back in from an input
stream:
Other structure types created by struct, which offer more abstraction than prefab structure
types, normally write either using #<....> notation (for opaque structure types) or using
#(....) vector notation (for transparent structure types). In neither can the result be read
back in as an instance of the structure type:
185
> (define-values (in out) (make-pipe))
> v
'#(struct:posn 1 2)
> (posn? v)
#f
> (vector? v)
#t
Examples:
186
> (deserialize (read in))
(posn 1 2)
In addition to the names bound by struct, serializable-struct binds an identifier
with deserialization information, and it automatically provides the deserialization identifier
from a module context. This deserialization identifier is accessed reflectively when a value
is deserialized.
Functions like read-line, read, display, and write all work in terms of characters
(which correspond to Unicode scalar values). Conceptually, they are implemented in terms
of read-char and write-char.
More primitively, ports read and write bytes, instead of characters. The functions read-
byte and write-byte read and write raw bytes. Other functions, such as read-bytes-
line, build on top of byte operations instead of character operations.
In fact, the read-char and write-char functions are conceptually implemented in terms
of read-byte and write-byte. When a single byte’s value is less than 128, then it corre-
sponds to an ASCII character. Any other byte is treated as part of a UTF-8 sequence, where
UTF-8 is a particular standard way of encoding Unicode scalar values in bytes (which has
the nice property that ASCII characters are encoded as themselves). Thus, a single read-
char may call read-byte multiple times, and a single write-char may generate multiple
output bytes.
The read-char and write-char operations always use a UTF-8 encoding. If you have a
text stream that uses a different encoding, or if you want to generate a text stream in a differ-
ent encoding, use reencode-input-port or reencode-output-port. The reencode-
input-port function converts an input stream from an encoding that you specify into a
UTF-8 stream; that way, read-char sees UTF-8 encodings, even though the original used a
different encoding. Beware, however, that read-byte also sees the re-encoded data, instead
of the original byte stream.
If you want to process individual lines of a file, then you can use for with in-lines:
> (define (upcase-all in)
(for ([l (in-lines in)])
(display (string-upcase l))
(newline)))
187
> (upcase-all (open-input-string
(string-append
"Hello, World!\n"
"Can you hear me, now?")))
HELLO, WORLD!
CAN YOU HEAR ME, NOW?
If you want to determine whether “hello” appears in a file, then you could search separate
lines, but it’s even easier to simply apply a regular expression (see §9 “Regular Expressions”)
to the stream:
If you want to copy one port into another, use copy-port from racket/port, which effi-
ciently transfers large blocks when lots of data is available, but also transfers small blocks
immediately if that’s all that is available:
> (get-output-string o)
"broom"
188
9 Regular Expressions
This chapter is a
modified version of
A regexp value encapsulates a pattern that is described by a string or byte string. The regexp [Sitaram05].
matcher tries to match this pattern against (a portion of) another string or byte string, which
we will call the text string, when you call functions like regexp-match. The text string is
treated as raw text, and not as a pattern. §3.7 “Regular
Expressions” in
The Racket
Reference provides
9.1 Writing Regexp Patterns more on regexps.
A string or byte string can be used directly as a regexp pattern, or it can be prefixed with
#rx to form a literal regexp value. For example, #rx"abc" is a string-based regexp value,
and #rx#"abc" is a byte string-based regexp value. Alternately, a string or byte string can
be prefixed with #px, as in #px"abc", for a slightly extended syntax of patterns within the
string.
Most of the characters in a regexp pattern are meant to match occurrences of themselves in
the text string. Thus, the pattern #rx"abc" matches a string that contains the characters a, b,
and c in succession. Other characters act as metacharacters, and some character sequences
act as metasequences. That is, they specify something other than their literal selves. For
example, in the pattern #rx"a.c", the characters a and c stand for themselves, but the
metacharacter . can match any character. Therefore, the pattern #rx"a.c" matches an a,
any character, and c in succession. When we want a
literal \ inside a
If we needed to match the character . itself, we can escape it by precede it with a \. The Racket string or
regexp literal, we
character sequence \. is thus a metasequence, since it doesn’t match itself but rather just .. must escape it so
So, to match a, ., and c in succession, we use the regexp pattern #rx"a\\.c"; the double \ that it shows up in
is an artifact of Racket strings, not the regexp pattern itself. the string at all.
Racket strings use \
The regexp function takes a string or byte string and produces a regexp value. Use reg- as the escape
character, so we end
exp when you construct a pattern to be matched against multiple strings, since a pattern up with two \s: one
is compiled to a regexp value before it can be used in a match. The pregexp function is Racket-string \ to
like regexp, but using the extended syntax. Regexp values as literals with #rx or #px are escape the regexp \,
which then escapes
compiled once and for all when they are read. the .. Another
character that
The regexp-quote function takes an arbitrary string and returns a string for a pattern that would need
matches exactly the original string. In particular, characters in the input string that could escaping inside a
serve as regexp metacharacters are escaped with a backslash, so that they safely match only Racket string is ".
themselves.
189
The regexp-quote function is useful when building a composite regexp from a mix of
regexp strings and verbatim strings.
The regexp-match-positions function takes a regexp pattern and a text string, and it
returns a match if the regexp matches (some part of) the text string, or #f if the regexp did
not match the string. A successful match produces a list of index pairs.
Examples:
In the second example, the integers 4 and 10 identify the substring that was matched. The 4 is
the starting (inclusive) index, and 10 the ending (exclusive) index of the matching substring:
In this first example, regexp-match-positions’s return list contains only one index pair,
and that pair represents the entire substring matched by the regexp. When we discuss sub-
patterns later, we will see how a single match operation can yield a list of submatches.
The regexp-match-positions function takes optional third and fourth arguments that
specify the indices of the text string within which the matching should take place.
> (regexp-match-positions
#rx"needle"
"his needle stack -- my needle stack -- her needle stack"
20 39)
'((23 . 29))
Note that the returned indices are still reckoned relative to the full text string.
190
When regexp-match is used with byte-string regexp, the result is a matching byte substring:
> (regexp-match #rx#"needle" #"hay needle stack")
'(#"needle")
A byte-string
regexp can be
If you have data that is in a port, there’s no need to first read it into a string. Functions like applied to a string,
and a string regexp
regexp-match can match on the port directly: can be applied to a
> (define-values (i o) (make-pipe)) byte string. In both
cases, the result is a
byte string.
> (write "hay needle stack" o) Internally, all
regexp matching is
> (close-output-port o) in terms of bytes,
and a string regexp
is expanded to a
> (regexp-match #rx#"needle" i) regexp that matches
'(#"needle") UTF-8 encodings of
characters. For
maximum
The regexp-match? function is like regexp-match-positions, but simply returns a efficiency, use
byte-string
boolean indicating whether the match succeeded: matching instead of
> (regexp-match? #rx"brain" "bird") string, since
matching bytes
#f directly avoids
> (regexp-match? #rx"needle" "hay needle stack") UTF-8 encodings.
#t
The regexp-split function takes two arguments, a regexp pattern and a text string, and it
returns a list of substrings of the text string; the pattern identifies the delimiter separating the
substrings.
> (regexp-split #rx":" "/bin:/usr/bin:/usr/bin/X11:/usr/local/bin")
'("/bin" "/usr/bin" "/usr/bin/X11" "/usr/local/bin")
> (regexp-split #rx" " "pea soup")
'("pea" "soup")
If the first argument matches empty strings, then the list of all the single-character substrings
is returned.
> (regexp-split #rx"" "smithereens")
'("" "s" "m" "i" "t" "h" "e" "r" "e" "e" "n" "s" "")
Thus, to identify one-or-more spaces as the delimiter, take care to use the regexp #rx" +",
not #rx" *".
> (regexp-split #rx" +" "split pea soup")
'("split" "pea" "soup")
> (regexp-split #rx" *" "split pea soup")
'("" "s" "p" "l" "i" "t" "" "p" "e" "a" "" "s" "o" "u" "p" "")
191
The regexp-replace function replaces the matched portion of the text string by another
string. The first argument is the pattern, the second the text string, and the third is either the
string to be inserted or a procedure to convert matches to the insert string.
> (regexp-replace #rx"te" "liberte" "ty")
"liberty"
> (regexp-replace #rx"." "racket" string-upcase)
"Racket"
If the pattern doesn’t occur in the text string, the returned string is identical to the text string.
The regexp-replace* function replaces all matches in the text string by the insert string:
> (regexp-replace* #rx"te" "liberte egalite fraternite" "ty")
"liberty egality fratyrnity"
> (regexp-replace* #rx"[ds]" "drracket" string-upcase)
"Drracket"
The assertions ^ and $ identify the beginning and the end of the text string, respectively.
They ensure that their adjoining regexps match at one or other end of the text string:
> (regexp-match-positions #rx"^contact" "first contact")
#f
The regexp above fails to match because contact does not occur at the beginning of the text
string. In
> (regexp-match-positions #rx"laugh$" "laugh laugh laugh laugh")
'((18 . 23))
The metasequence \b asserts that a word boundary exists, but this metasequence works only
with #px syntax. In
> (regexp-match-positions #px"yack\\b" "yackety yack")
'((8 . 12))
the yack in yackety doesn’t end at a word boundary so it isn’t matched. The second yack
does and is.
The metasequence \B (also #px only) has the opposite effect to \b; it asserts that a word
boundary does not exist. In
192
> (regexp-match-positions #px"an\\B" "an analysis")
'((3 . 5))
Typically, a character in the regexp matches the same character in the text string. Sometimes
it is necessary or convenient to use a regexp metasequence to refer to a single character. For
example, the metasequence \. matches the period character.
The metacharacter . matches any character (other than newline in multi-line mode; see
§9.6.3 “Cloisters”):
> (regexp-match #rx"p.t" "pet")
'("pet")
The above pattern also matches pat, pit, pot, put, and p8t, but not peat or pfffft.
A character class matches any one character from a set of characters. A typical format
for this is the bracketed character class [...], which matches any one character from the
non-empty sequence of characters enclosed within the brackets. Thus, #rx"p[aeiou]t"
matches pat, pet, pit, pot, put, and nothing else.
Inside the brackets, a - between two characters specifies the Unicode range between the
characters. For example, #rx"ta[b-dgn-p]" matches tab, tac, tad, tag, tan, tao, and
tap.
An initial ^ after the left bracket inverts the set specified by the rest of the contents; i.e.,
it specifies the set of characters other than those identified in the brackets. For example,
#rx"do[^g]" matches all three-character sequences starting with do except dog.
Note that the metacharacter ^ inside brackets means something quite different from what it
means outside. Most other metacharacters (., *, +, ?, etc.) cease to be metacharacters when
inside brackets, although you may still escape them for peace of mind. A - is a metacharacter
only when it’s inside brackets, and when it is neither the first nor the last character between
the brackets.
Bracketed character classes cannot contain other bracketed character classes (although they
contain certain other types of character classes; see below). Thus, a [ inside a bracketed
character class doesn’t have to be a metacharacter; it can stand for itself. For example,
#rx"[a[b]" matches a, [, and b.
Furthermore, since empty bracketed character classes are disallowed, a ] immediately oc-
curring after the opening left bracket also doesn’t need to be a metacharacter. For example,
193
#rx"[]ab]" matches ], a, and b.
In #px syntax, some standard character classes can be conveniently represented as metase-
quences instead of as explicit bracketed expressions: \d matches a digit (the same as [0-9]);
\s matches an ASCII whitespace character; and \w matches a character that could be part of
a “word”. Following regexp
custom, we identify
The upper-case versions of these metasequences stand for the inversions of the correspond- “word” characters
as [A-Za-z0-9_],
ing character classes: \D matches a non-digit, \S a non-whitespace character, and \W a although these are
non-“word” character. too restrictive for
what a Racketeer
Remember to include a double backslash when putting these metasequences in a Racket might consider a
string: “word.”
These character classes can be used inside a bracketed expression. For example, #px"[a-
z\\d]" matches a lower-case letter or a digit.
A POSIX character class is a special metasequence of the form [:...:] that can be used only
inside a bracketed expression in #px syntax. The POSIX classes supported are
194
• [:space:] — ASCII whitespace, same as \s
• [:upper:] — ASCII upper-case letters
• [:word:] — ASCII letters and _, same as \w
• [:xdigit:] — ASCII hex digits
The POSIX class notation is valid only inside a bracketed expression. For instance,
[:alpha:], when not inside a bracketed expression, will not be read as the letter class.
Rather, it is (from previous principles) the character class containing the characters :, a, l,
p, h.
> (regexp-match #px"[:alpha:]" "--a--")
'("a")
> (regexp-match #px"[:alpha:]" "--x--")
#f
9.5 Quantifiers
The quantifiers *, +, and ? match respectively: zero or more, one or more, and zero or one
instances of the preceding subpattern.
> (regexp-match-positions #rx"c[ad]*r" "cadaddadddr")
'((0 . 11))
> (regexp-match-positions #rx"c[ad]*r" "cr")
'((0 . 2))
> (regexp-match-positions #rx"c[ad]+r" "cadaddadddr")
'((0 . 11))
> (regexp-match-positions #rx"c[ad]+r" "cr")
#f
> (regexp-match-positions #rx"c[ad]?r" "cadaddadddr")
#f
> (regexp-match-positions #rx"c[ad]?r" "cr")
'((0 . 2))
> (regexp-match-positions #rx"c[ad]?r" "car")
'((0 . 3))
195
In #px syntax, you can use braces to specify much finer-tuned quantification than is possible
with *, +, ?:
• The quantifier {m} matches exactly m instances of the preceding subpattern; m must
be a nonnegative integer.
• The quantifier {m,n} matches at least m and at most n instances. m and n are non-
negative integers with m less or equal to n. You may omit either or both numbers, in
which case m defaults to 0 and n to infinity.
It is evident that + and ? are abbreviations for {1,} and {0,1} respectively, and * abbreviates
{,}, which is the same as {0,}.
The quantifiers described so far are all greedy: they match the maximal number of instances
that would still lead to an overall match for the full pattern.
The non-greedy quantifiers are respectively: *?, +?, ??, {m}?, {m,n}?. Note the two uses
of the metacharacter ?.
9.6 Clusters
196
> (regexp-match #rx"([a-z]+) ([0-9]+), ([0-9]+)" "jan 1, 1970")
'("jan 1, 1970" "jan" "1" "1970")
Clustering also causes a following quantifier to treat the entire enclosed subpattern as an
entity:
The number of submatches returned is always equal to the number of subpatterns specified
in the regexp, even if a particular subpattern happens to match more than one substring or
no substring at all.
Here, the *-quantified subpattern matches three times, but it is the last submatch that is
returned.
It is also possible for a quantified subpattern to fail to match, even if the overall pattern
matches. In such cases, the failing submatch is represented by #f
9.6.1 Backreferences
Submatches can be used in the insert string argument of the procedures regexp-replace
and regexp-replace*. The insert string can use \n as a backreference to refer back to the
nth submatch, which is the substring that matched the nth subpattern. A \0 refers to the
entire match, and it can also be specified as \&.
197
> (regexp-replace* #rx"_(.+?)_"
"the _nina_, the _pinta_, and the _santa maria_"
"*\\1*")
"the *nina*, the *pinta*, and the *santa maria*"
> (regexp-replace #px"(\\S+) (\\S+) (\\S+)"
"eat to live"
"\\3 \\2 \\1")
"live to eat"
Use \\ in the insert string to specify a literal backslash. Also, \$ stands for an empty string,
and is useful for separating a backreference \n from an immediately following number.
Backreferences can also be used within a #px pattern to refer back to an already matched
subpattern in the pattern. \n stands for an exact repeat of the nth submatch. Note that \0,
which is useful in an insert string, makes no sense within the regexp pattern, because the
entire regexp has not matched yet so you cannot refer back to it.}
> (regexp-match #px"([a-z]+) and \\1"
"billions and billions")
'("billions and billions" "billions")
Note that the backreference is not simply a repeat of the previous subpattern. Rather it is a
repeat of the particular substring already matched by the subpattern.
In the above example, the backreference can only match billions. It will not match
millions, even though the subpattern it harks back to—([a-z]+)—would have had no
problem doing so:
> (regexp-match #px"([a-z]+) and \\1"
"billions and millions")
#f
The following example marks all immediately repeating patterns in a number string:
> (regexp-replace* #px"(\\d+)\\1"
"123340983242432420980980234"
"{\\1,\\1}")
"12{3,3}40983{24,24}3242{098,098}0234"
198
9.6.2 Non-capturing Clusters
It is often required to specify a cluster (typically for quantification) but without triggering
the capture of submatch information. Such clusters are called non-capturing. To create a
non-capturing cluster, use (?: instead of ( as the cluster opener.
9.6.3 Cloisters
The location between the ? and the : of a non-capturing cluster is called a cloister. You can
put modifiers there that will cause the enclustered subpattern to be treated specially. The
modifier i causes the subpattern to match case-insensitively: The term cloister is
a useful, if
> (regexp-match #rx"(?i:hearth)" "HeartH") terminally cute,
'("HeartH") coinage from the
abbots of Perl.
The modifier m causes the subpattern to match in multi-line mode, where . does not match a
newline character, ^ can match just after a newline, and $ can match just before a newline.
> (regexp-match #rx"." "\na\n")
'("\n")
> (regexp-match #rx"(?m:.)" "\na\n")
'("a")
> (regexp-match #rx"^A plan$" "A man\nA plan\nA canal")
#f
> (regexp-match #rx"(?m:^A plan$)" "A man\nA plan\nA canal")
'("A plan")
A minus sign before a modifier inverts its meaning. Thus, you can use -i in a subcluster to
overturn the case-insensitivities caused by an enclosing cluster.
> (regexp-match #rx"(?i:the (?-i:TeX)book)"
"The TeXbook")
'("The TeXbook")
199
The above regexp will allow any casing for the and book, but it insists that TeX not be
differently cased.
9.7 Alternation
You can specify a list of alternate subpatterns by separating them by |. The | separates
subpatterns in the nearest enclosing cluster (or in the entire pattern string if there are no
enclosing parens).
> (regexp-match #rx"f(ee|i|o|um)" "a small, final fee")
'("fi" "i")
> (regexp-replace* #rx"([yi])s(e[sdr]?|ing|ation)"
(string-append
"analyse an energising organisation"
" pulsing with noisy organisms")
"\\1z\\2")
"analyze an energizing organization pulsing with noisy organisms"
Note again that if you wish to use clustering merely to specify a list of alternate subpatterns
but do not want the submatch, use (?: instead of (.
> (regexp-match #rx"f(?:ee|i|o|um)" "fun for all")
'("fo")
An important thing to note about alternation is that the leftmost matching alternate is picked
regardless of its length. Thus, if one of the alternates is a prefix of a later alternate, the latter
may not have a chance to match.
> (regexp-match #rx"call|call-with-current-continuation"
"call-with-current-continuation")
'("call")
To allow the longer alternate to have a shot at matching, place it before the shorter one:
> (regexp-match #rx"call-with-current-continuation|call"
"call-with-current-continuation")
'("call-with-current-continuation")
In any case, an overall match for the entire regexp is always preferred to an overall non-
match. In the following, the longer alternate still wins, because its preferred shorter prefix
fails to yield an overall match.
> (regexp-match
#rx"(?:call|call-with-current-continuation) constrained"
"call-with-current-continuation constrained")
'("call-with-current-continuation constrained")
200
9.8 Backtracking
We’ve already seen that greedy quantifiers match the maximal number of times, but the
overriding priority is that the overall match succeed. Consider
> (regexp-match #rx"a*a" "aaaa")
'("aaaa")
The regexp matcher accomplishes this via a process called backtracking. The matcher tenta-
tively allows the greedy quantifier to match all four a’s, but then when it becomes clear that
the overall match is in jeopardy, it backtracks to a less greedy match of three a’s. If even this
fails, as in the call
> (regexp-match #rx"a*aa" "aaaa")
'("aaaa")
the matcher backtracks even further. Overall failure is conceded only when all possible
backtracking has been tried with no success.
In this call, the subregexp ?>a+ greedily matches all four a’s, and is denied the opportunity
to backtrack. So, the overall match is denied. The effect of the regexp is therefore to match
one or more a’s followed by something that is definitely non-a.
You can have assertions in your pattern that look ahead or behind to ensure that a subpattern
does or does not occur. These “look around” assertions are specified by putting the subpat-
tern checked for in a cluster whose leading characters are: ?= (for positive lookahead), ?!
201
(negative lookahead), ?<= (positive lookbehind), ?<! (negative lookbehind). Note that the
subpattern in the assertion does not generate a match in the final result; it merely allows or
disallows the rest of the match.
9.9.1 Lookahead
Positive lookahead with ?= peeks ahead to ensure that its subpattern could match.
The regexp #rx"grey(?=hound)" matches grey, but only if it is followed by hound. Thus,
the first grey in the text string is not matched.
Negative lookahead with ?! peeks ahead to ensure that its subpattern could not possibly
match.
The regexp #rx"grey(?!hound)" matches grey, but only if it is not followed by hound.
Thus the grey just before socks is matched.
9.9.2 Lookbehind
Positive lookbehind with ?<= checks that its subpattern could match immediately to the left
of the current position in the text string.
Negative lookbehind with ?<! checks that its subpattern could not possibly match immedi-
ately to the left.
202
The regexp #rx"(?<!grey)hound" matches hound, but only if it is not preceded by grey.
Lookaheads and lookbehinds can be convenient when they are not confusing.
Here’s an extended example from Friedl’s Mastering Regular Expressions, page 189, that
covers many of the features described in this chapter. The problem is to fashion a regexp
that will match any and only IP addresses or dotted quads: four numbers separated by three
dots, with each number between 0 and 255.
203
> (regexp-match (pregexp ip-re1) "1.2.3.4")
'("1.2.3.4")
> (regexp-match (pregexp ip-re1) "55.155.255.265")
#f
All-zero sequences are not valid IP addresses! Lookahead to the rescue. Before starting
to match ip-re1, we look ahead to ensure we don’t have all zeros. We could use positive
lookahead to ensure there is a digit other than zero.
Or we could use negative lookahead to ensure that what’s ahead isn’t composed of only zeros
and dots.
The regexp ip-re will match all and only valid IP addresses.
204
10 Exceptions and Control
Racket provides an especially rich set of control operations—not only operations for rais-
ing and catching exceptions, but also operations for grabbing and restoring portions of a
computation.
10.1 Exceptions
Whenever a run-time error occurs, an exception is raised. Unless the exception is caught,
then it is handled by printing a message associated with the exception, and then escaping
from the computation.
> (/ 1 0)
/: division by zero
> (car 17)
car: contract violation
expected: pair?
given: 17
205
The error function is one way to raise your own exception. It packages an error message
and other information into an exn:fail structure:
> (error "crash!")
crash!
> (with-handlers ([exn:fail? (lambda (exn) 'air-bag)])
(error "crash!"))
'air-bag
> (always-fail 2)
'even
> (always-fail 3)
'positive
> (always-fail -3)
uncaught exception: -3
> (with-handlers ([negative? (lambda (v) 'negative)])
(always-fail -3))
'negative
206
Capturing all exceptions is usually a bad idea, however. If the user types Ctl-C in a terminal
window or clicks the Stop button in DrRacket to interrupt a computation, then normally the
exn:break exception should not be caught. To catch only exceptions that represent errors,
use exn:fail? as the predicate:
When an exception is raised, control escapes out of an arbitrary deep evaluation context to
the point where the exception is caught—or all the way out if the exception is never caught:
> (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (/ 1 0)))))))
/: division by zero
But if control escapes “all the way out,” why does the REPL keep going after an error is
printed? You might think that it’s because the REPL wraps every interaction in a with-
handlers form that catches all exceptions, but that’s not quite the reason.
The actual reason is that the REPL wraps the interaction with a prompt, which effectively
marks the evaluation context with an escape point. If an exception is not caught, then in-
formation about the exception is printed, and then evaluation aborts to the nearest enclosing
prompt. More precisely, each prompt has a prompt tag, and there is a designated default
prompt tag that the uncaught-exception handler uses to abort.
207
(lambda ()
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (escape 0))))))))
(default-continuation-prompt-tag)))
1
In escape above, the value v is wrapped in a procedure that is called after escaping to the
enclosing prompt.
Prompts and aborts look very much like exception handling and raising. Indeed, prompts
and aborts are essentially a more primitive form of exceptions, and with-handlers and
raise are implemented in terms of prompts and aborts. The power of the more primitive
forms is related to the word “continuation” in the operator names, as we discuss in the next
section.
10.3 Continuations
For example, in
(+ 1 (+ 1 (+ 1 0)))
at the point where 0 is evaluated, the expression context includes three nested addition ex-
pressions. We can grab that context by changing 0 to grab the continuation before returning
0:
> (define saved-k #f)
> (+ 1 (+ 1 (+ 1 (save-it!))))
3
208
> (saved-k 0)
3
> (saved-k 10)
13
> (saved-k (saved-k 0))
6
> (sum 5)
15
> (saved-k 0)
15
> (saved-k 10)
25
For an example of how continuations are useful, see More: Systems Programming with
Racket. For specific control operators that have more convenient names than the primitives
described here, see racket/control.
209
11 Iterations and Comprehensions
The for family of syntactic forms support iteration over sequences. Lists, vectors, strings,
byte strings, input ports, and hash tables can all be used as sequences, and constructors like
in-range offer even more kinds of sequences.
Variants of for accumulate iteration results in different ways, but they all have the same
syntactic shape. Simplifying for now, the syntax of for is
A for loop iterates through the sequence produced by the sequence-expr . For each ele-
ment of the sequence, for binds the element to id , and then it evaluates the body s for side
effects.
Examples:
The for/list variant of for is more Racket-like. It accumulates body results into a list,
instead of evaluating body only for side effects. In more technical terms, for/list imple-
ments a list comprehension.
Examples:
210
'(0 1 2 3)
The full syntax of for accommodates multiple sequences to iterate in parallel, and the for*
variant nests the iterations instead of running them in parallel. More variants of for and
for* accumulate body results in different ways. In all of these variants, predicates that
prune iterations can be included along with bindings.
Before details on the variations of for, though, it’s best to see the kinds of sequence gener-
ators that make interesting examples.
The in-range function generates a sequence of numbers, given an optional starting number
(which defaults to 0), a number before which the sequence ends, and an optional step (which
defaults to 1). Using a non-negative integer k directly as a sequence is a shorthand for
(in-range k ).
Examples:
> (for ([i 3])
(display i))
012
The in-naturals function is similar, except that the starting number must be an exact non-
negative integer (which defaults to 0), the step is always 1, and there is no upper limit. A
211
for loop using just in-naturals will never terminate unless a body expression raises an
exception or otherwise escapes.
Example:
The stop-before and stop-after functions construct a new sequence given a sequence
and a predicate. The new sequence is like the given sequence, but truncated either immedi-
ately before or immediately after the first element for which the predicate returns true.
Example:
Sequence constructors like in-list, in-vector and in-string simply make explicit the
use of a list, vector, or string as a sequence. Along with in-range, these constructors raise
an exception when given the wrong kind of value, and since they otherwise avoid a run-time
dispatch to determine the sequence type, they enable more efficient code generation; see
§11.10 “Iteration Performance” for more information.
Examples:
212
(for (clause ...)
body ...+)
When multiple [id sequence-expr ] clauses are provided in a for form, the correspond-
ing sequences are traversed in parallel:
With parallel sequences, the for expression stops iterating when any sequence ends. This
behavior allows in-naturals, which creates an infinite sequence of numbers, to be used
for indexing:
The for* form, which has the same syntax as for, nests multiple sequences instead of
running them in parallel:
213
Thus, for* is a shorthand for nested fors in the same way that let* is a shorthand for
nested lets.
The #:when boolean-expr form of a clause is another shorthand. It allows the body s
to evaluate only when the boolean-expr produces a true value:
A boolean-expr with #:when can refer to any of the preceding iteration bindings. In a
for form, this scoping makes sense only if the test is nested in the iteration of the preceding
bindings; thus, bindings separated by #:when are mutually nested, instead of in parallel,
even with for.
An #:unless clause is analogus to a #:when clause, but the body s evaluate only when the
boolean-expr produces a false value.
The for/list form, which has the same syntax as for, evaluates the body s to obtain values
that go into a newly constructed list:
214
[chapter '("Intro" "Details" "Conclusion")])
(string-append (number->string i) ". " chapter))
'("1. Intro" "2. Details" "3. Conclusion")
A #:when clause in a for-list form prunes the result list along with evaluations of the
body s:
> (for/list ([i (in-naturals 1)]
[chapter '("Intro" "Details" "Conclusion")]
#:when (odd? i))
chapter)
'("Intro" "Conclusion")
This pruning behavior of #:when is more useful with for/list than for. Whereas a plain
when form normally suffices with for, a when expression form in a for/list would cause
the result list to contain #<void>s instead of omitting list elements.
A for*/list form is not quite the same thing as nested for/list forms. Nested
for/lists would produce a list of lists, instead of one flattened list. Much like #:when,
then, the nesting of for*/list is more useful than the nesting of for*.
The for/vector form can be used with the same syntax as the for/list form, but the
evaluated body s go into a newly-constructed vector instead of a list:
The for*/vector form behaves similarly, but the iterations are nested as in for*.
The for/vector and for*/vector forms also allow the length of the vector to be con-
structed to be supplied in advance. The resulting iteration can be performed more efficiently
than plain for/vector or for*/vector:
215
> (let ([chapters '("Intro" "Details" "Conclusion")])
(for/vector #:length (length chapters) ([i (in-naturals 1)]
[chapter chapters])
(string-append (number->string i) ". " chapter)))
'#("1. Intro" "2. Details" "3. Conclusion")
If a length is provided, the iteration stops when the vector is filled or the requested iterations
are complete, whichever comes first. If the provided length exceeds the requested number
of iterations, then the remaining slots in the vector are initialized to the default argument of
make-vector.
The for/and form combines iteration results with and, stopping as soon as it encounters
#f:
> (for/and ([chapter '("Intro" "Details" "Conclusion")])
(equal? chapter "Intro"))
#f
The for/or form combines iteration results with or, stopping as soon as it encounters a true
value:
> (for/or ([chapter '("Intro" "Details" "Conclusion")])
(equal? chapter "Intro"))
#t
As usual, the for*/and and for*/or forms provide the same facility with nested iterations.
The for/first form returns the result of the first time that the body s are evaluated, skip-
ping further iterations. This form is most useful with a #:when clause.
> (for/first ([chapter '("Intro" "Details" "Conclusion" "Index")]
#:when (not (equal? chapter "Intro")))
chapter)
"Details"
If the body s are evaluated zero times, then the result is #f.
The for/last form runs all iterations, returning the value of the last iteration (or #f if no
iterations are run):
216
> (for/last ([chapter '("Intro" "Details" "Conclusion" "Index")]
#:when (not (equal? chapter "Index")))
chapter)
"Conclusion"
As usual, the for*/first and for*/last forms provide the same facility with nested
iterations:
The for/fold form is a very general way to combine iteration results. Its syntax is slightly
different than the syntax of for, because accumulation variables must be declared at the
beginning:
In the simple case, only one [accum-id init-expr ] is provided, and the result of the
for/fold is the final value for accum-id , which starts out with the value of init-expr .
In the clause s and body s, accum-id can be referenced to get its current value, and the last
body provides the value of accum-id for the next iteration.
Examples:
217
(printf "∼a. ∼a\n" i chapter)
chapter)
1. Intro
2. Details
4. Conclusion
"Conclusion"
When multiple accum-id s are specified, then the last body must produce multiple values,
one for each accum-id . The for/fold expression itself produces multiple values for the
results.
Example:
In the same way that a function or expression can produce multiple values, individual itera-
tions of a sequence can produce multiple elements. For example, a hash table as a sequence
generates two values for each iteration: a key and a value.
In the same way that let-values binds multiple results to multiple identifiers, for can bind
multiple sequence elements to multiple iteration identifiers: While let must be
changed to
> (for ([(k v) #hash(("apple" . 1) ("banana" . 3))]) let-values to
bind multiple
(printf "∼a count: ∼a\n" k v)) identifiers, for
apple count: 1 simply allows a
banana count: 3 parenthesized list of
identifiers instead
of a single identifier
in any clause.
This extension to multiple-value bindings works for all for variants. For example,
for*/list nests iterations, builds a list, and also works with multiple-valued sequences:
218
[(i) (in-range v)])
k)
'("apple" "banana" "banana" "banana")
body-or-break = body
| break
That is, a #:break or #:final clause can be included among the binding clauses and
body of the iteration. Among the binding clauses, #:break is like #:unless but when
its boolean-expr is true, all sequences within the for are stopped. Among the body s,
#:break has the same effect on sequences when its boolean-expr is true, and it also pre-
vents later body s from evaluation in the current iteration.
For example, while using #:when between clauses effectively skips later sequences as well
as the body,
> (for ([book '("Guide" "Story" "Reference")]
#:unless (equal? book "Story")
[chapter '("Intro" "Details" "Conclusion")])
(printf "∼a ∼a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
Reference Intro
Reference Details
Reference Conclusion
219
> (for ([book '("Guide" "Story" "Reference")]
#:break (equal? book "Story")
[chapter '("Intro" "Details" "Conclusion")])
(printf "∼a ∼a\n" book chapter))
Guide Intro
Guide Details
Guide Conclusion
A #:final clause is similar to #:break, but it does not immediately terminate the iteration.
Instead, it allows at most one more element to be drawn for each sequence and at most one
more evaluation of the body s.
220
11.10 Iteration Performance
Ideally, a for iteration should run as fast as a loop that you write by hand as a recursive-
function invocation. A hand-written loop, however, is normally specific to a particular kind
of data, such as lists. In that case, the hand-written loop uses selectors like car and cdr
directly, instead of handling all forms of sequences and dispatching to an appropriate iterator.
The for forms can provide the performance of hand-written loops when enough information
is apparent about the sequences to iterate. Specifically, the clause should have one of the
following fast-clause forms:
Examples:
221
cpu time: 39 real time: 39 gc time: 0
The grammars above are not complete, because the set of syntactic patterns that provide
good performance is extensible, just like the set of sequence values. The documentation for
a sequence constructor should indicate the performance benefits of using it directly in a for
clause . §2.18 “Iterations
and
Comprehensions:
for, for/list, ...”
in The Racket
Reference provides
more on iterations
and
comprehensions.
222
12 Pattern Matching
The match form supports pattern matching on arbitrary Racket values, as opposed to func-
tions like regexp-match that compare regular expressions to byte and character sequences
(see §9 “Regular Expressions”).
(match target-expr
[pattern expr ...+] ...)
The match form takes the result of target-expr and tries to match each pattern in order.
As soon as it finds a match, it evaluates the corresponding expr sequence to obtain the result
for the match form. If pattern includes pattern variables, they are treated like wildcards,
and each variable is bound in the expr to the input fragments that it matched.
Constructors like cons, list, and vector can be used to create patterns that match pairs,
lists, and vectors:
> (match '(1 2)
[(list 0 1) 'one]
[(list 1 2) 'two])
'two
> (match '(1 . 2)
[(list 1 2) 'list]
[(cons 1 2) 'pair])
'pair
> (match #(1 2)
[(list 1 2) 'list]
[(vector 1 2) 'vector])
223
'vector
Unquoted, non-constructor identifiers in a pattern are pattern variables that are bound in the
result expressions:
An ellipsis, written ..., acts like a Kleene star within a list or vector pattern: the preced-
ing sub-pattern can be used to match any number of times for any number of consecutive
elements of the list or vector. If a sub-pattern followed by an ellipsis includes a pattern vari-
able, the variable matches multiple times, and it is bound in the result expression to a list of
matches:
224
'(2 3)
> (match (list (hat 23 'bowler) (hat 22 'pork-pie))
[(list (hat sz styl) ...) (apply + sz)])
45
Ellipses can be nested to match nested repetitions, and in that case, pattern variables can be
bound to lists of lists of matches:
The quasiquote form (see §4.11 “Quasiquoting: quasiquote and `” for more about it)
can also be used to build patterns. While unquoted portions of a normal quasiquoted form
mean regular racket evaluation, here unquoted portions mean go back to regular pattern
matching.
So, in the example below, the with expression is the pattern and it gets rewritten into the
application expression, using quasiquote as a pattern in the first instance and quasiquote to
build an expression in the second.
Forms like match-let and match-lambda support patterns in positions that otherwise must
be identifiers. For example, match-let generalizes let to a destructing bind:
225
13 Classes and Objects
This chapter is
based on a paper
A class expression denotes a first-class value, just like a lambda expression: [Flatt06].
The superclass-expr determines the superclass for the new class. Each decl-or-expr
is either a declaration related to methods, fields, and initialization arguments, or it is an
expression that is evaluated each time that the class is instantiated. In other words, instead
of a method-like constructor, a class has initialization expressions interleaved with field and
method declarations.
By convention, class names end with %. The built-in root class is object%. The following
expression creates a class with public methods get-size, grow, and eat:
(class object%
(init size) ; initialization argument
(define/public (get-size)
current-size)
The size initialization argument must be supplied via a named argument when instantiating
the class through the new form:
In the definition of fish%, current-size is a private field that starts out with the value of
the size initialization argument. Initialization arguments like size are available only during
226
class instantiation, so they cannot be referenced directly from a method. The current-size
field, in contrast, is available to methods.
The (super-new) expression in fish% invokes the initialization of the superclass. In this
case, the superclass is object%, which takes no initialization arguments and performs no
work; super-new must be used, anyway, because a class must always invoke its superclass’s
initialization.
Initialization arguments, field declarations, and expressions such as (super-new) can ap-
pear in any order within a class, and they can be interleaved with method declarations.
The relative order of expressions in the class determines the order of evaluation during in-
stantiation. For example, if a field’s initial value requires calling a method that works only
after superclass initialization, then the field declaration must be placed after the super-new
call. Ordering field and initialization declarations in this way helps avoid imperative assign-
ment. The relative order of method declarations makes no difference for evaluation, because
methods are fully defined before a class is instantiated.
13.1 Methods
Each of the three define/public declarations in fish% introduces a new method. The
declaration uses the same syntax as a Racket function, but a method is not accessible as an
independent function. A call to the grow method of a fish% object requires the send form:
> (send charlie grow 6)
Within fish%, self methods can be called like functions, because the method names are
in scope. For example, the eat method within fish% directly invokes the grow method.
Within a class, attempting to use a method name in any way other than a method call results
in a syntax error.
In some cases, a class must call methods that are supplied by the superclass but not overrid-
den. In that case, the class can use send with this to access the method:
(define hungry-fish% (class fish% (super-new)
(define/public (eat-more fish1 fish2)
(send this eat fish1)
(send this eat fish2))))
Alternately, the class can declare the existence of a method using inherit, which brings the
method name into scope for a direct call:
227
(define hungry-fish% (class fish% (super-new)
(inherit eat)
(define/public (eat-more fish1 fish2)
(eat fish1) (eat fish2))))
With the inherit declaration, if fish% had not provided an eat method, an error would be
signaled in the evaluation of the class form for hungry-fish%. In contrast, with (send
this ....), an error would not be signaled until the eat-more method is called and the
send form is evaluated. For this reason, inherit is preferred.
Another drawback of send is that it is less efficient than inherit. Invocation of a method
via send involves finding a method in the target object’s class at run time, making send
comparable to an interface-based method call in Java. In contrast, inherit-based method
invocations use an offset within the class’s method table that is computed when the class is
created.
Roughly speaking, the form translates the class and the external method name to a location
in the class’s method table. As illustrated by the last example, sending through a generic
method checks that its argument is an instance of the generic’s class.
Whether a method is called directly within a class, through a generic method, or through
send, method overriding works in the usual way:
(define picky-fish% (class fish% (super-new)
(define/override (grow amt)
228
> (send daisy eat charlie)
Using define/override also allows the invocation of the overridden method via a super
call. For example, the grow implementation in picky-fish% uses super to delegate to the
superclass implementation.
In the case of size-10-fish%, supplying a size initialization argument with new would
result in an initialization error; because the size in super-new takes precedence, a size
supplied to new would have no target declaration.
An initialization argument is optional if the class form declares a default value. For exam-
ple, the following default-10-fish% class accepts a size initialization argument, but its
value defaults to 10 if no value is supplied on instantiation:
229
In this example, the super-new call propagates its own size value as the size initialization
argument to the superclass.
The two uses of size in default-10-fish% expose the double life of class-member iden-
tifiers. When size is the first identifier of a bracketed pair in new or super-new, size is an
external name that is symbolically matched to an initialization argument in a class. When
size appears as an expression within default-10-fish%, size is an internal name that is
lexically scoped. Similarly, a call to an inherited eat method uses eat as an internal name,
whereas a send of eat uses eat as an external name.
The full syntax of the class form allows a programmer to specify distinct internal and
external names for a class member. Since internal names are local, they can be renamed to
avoid shadowing or conflicts. Such renaming is not frequently necessary, but workarounds
in the absence of renaming can be especially cumbersome.
13.4 Interfaces
Interfaces are useful for checking that an object or a class implements a set of methods with
a particular (implied) behavior. This use of interfaces is helpful even without a static type
system (which is the main reason that Java has interfaces).
An interface in Racket is created using the interface form, which merely declares the
method names required to implement the interface. An interface can extend other interfaces,
which means that implementations of the interface automatically implement the extended
interfaces.
To declare that a class implements an interface, the class* form must be used instead of
class:
For example, instead of forcing all fish classes to be derived from fish%, we can de-
fine fish-interface and change the fish% class to declare that it implements fish-
interface:
(define fish-interface (interface () get-size grow eat))
(define fish% (class* object% (fish-interface) ....))
230
If the definition of fish% does not include get-size, grow, and eat methods, then an
error is signaled in the evaluation of the class* form, because implementing the fish-
interface interface requires those methods.
The is-a? predicate accepts either a class or interface as its first argument and an object as
its second argument. When given a class, is-a? checks whether the object is an instance of
that class or a derived class. When given an interface, is-a? checks whether the object’s
class implements the interface. In addition, the implementation? predicate checks whether
a given class implements a given interface.
As in Java, a method in a class form can be specified as final, which means that a subclass
cannot override the method. A final method is declared using public-final or override-
final, depending on whether the declaration is for a new method or an overriding imple-
mentation.
Between the extremes of allowing arbitrary overriding and disallowing overriding entirely,
the class system also supports Beta-style augmentable methods [Goldberg04]. A method
declared with pubment is like public, but the method cannot be overridden in subclasses;
it can be augmented only. A pubment method must explicitly invoke an augmentation (if
any) using inner; a subclass augments the method using augment, instead of override.
In general, a method can switch between augment and override modes in a class deriva-
tion. The augride method specification indicates an augmentation to a method where the
augmentation is itself overrideable in subclasses (though the superclass’s implementation
cannot be overridden). Similarly, overment overrides a method and makes the overriding
implementation augmentable.
231
During its evaluation, the hungry-fish% and fish% classes refer to the same global binding
of eat. At run time, calls to eat in hungry-fish% are matched with the eat method in
fish% through the shared method key that is bound to eat.
The default binding for an external name is global, but a programmer can introduce an
external-name binding with the define-member-name form.
(define-member-name id member-key-expr )
For example, the following fish% and pond% classes cooperate via a get-depth method
that is only accessible to the cooperating classes:
(define-values (fish% pond%) ; two mutually recursive classes
(let ()
(define-member-name get-depth (generate-member-key))
(define fish%
(class ....
(define my-depth ....)
(define my-pond ....)
(define/public (dive amt)
(set! my-depth
(min (+ my-depth amt)
(send my-pond get-depth))))))
(define pond%
(class ....
(define current-depth ....)
(define/public (get-depth) current-depth)))
(values fish% pond%)))
External names are in a namespace that separates them from other Racket names. This sep-
arate namespace is implicitly used for the method name in send, for initialization-argument
names in new, or for the external name in a member definition. The special form member-
name-key provides access to the binding of an external name in an arbitrary expression
position: (member-name-key id) produces the member-key binding of id in the current
scope.
232
13.7 Mixins
For example, we can parameterize the picky-fish% class over its superclass to define
picky-mixin:
(define (picky-mixin %)
(class % (super-new)
(define/override (grow amt) (super grow (* 3/4 amt)))))
(define picky-fish% (picky-mixin fish%))
Many small differences between Smalltalk-style classes and Racket classes contribute to
the effective use of mixins. In particular, the use of define/override makes explicit that
picky-mixin expects a class with a grow method. If picky-mixin is applied to a class
without a grow method, an error is signaled as soon as picky-mixin is applied.
Similarly, a use of inherit enforces a “method existence” requirement when the mixin is
applied:
(define (hungry-mixin %)
(class % (super-new)
(inherit eat)
(define/public (eat-more fish1 fish2)
(eat fish1)
(eat fish2))))
The advantage of mixins is that we can easily combine them to create new classes whose im-
plementation sharing does not fit into a single-inheritance hierarchy—without the ambigui-
ties associated with multiple inheritance. Equipped with picky-mixin and hungry-mixin,
creating a class for a hungry, yet picky fish is straightforward:
(define picky-hungry-fish%
(hungry-mixin (picky-mixin fish%)))
The use of keyword initialization arguments is critical for the easy use of mixins. For exam-
ple, picky-mixin and hungry-mixin can augment any class with suitable eat and grow
methods, because they do not specify initialization arguments and add none in their super-
new expressions:
(define person%
(class object%
(init name age)
233
....
(define/public (eat food) ....)
(define/public (grow amt) ....)))
(define child% (hungry-mixin (picky-mixin person%)))
(define oliver (new child% [name "Oliver"] [age 6]))
Finally, the use of external names for class members (instead of lexically scoped identifiers)
makes mixin use convenient. Applying picky-mixin to person% works because the names
eat and grow match, without any a priori declaration that eat and grow should be the
same method in fish% and person%. This feature is a potential drawback when member
names collide accidentally; some accidental collisions can be corrected by limiting the scope
external names, as discussed in §13.6 “Controlling the Scope of External Names”.
Using implementation?, picky-mixin could require that its base class implements
grower-interface, which could be implemented by both fish% and person%:
Another use of interfaces with a mixin is to tag classes generated by the mixin, so that
instances of the mixin can be recognized. In other words, is-a? cannot work on a mixin
represented as a function, but it can recognize an interface (somewhat like a specialization
interface) that is consistently implemented by the mixin. For example, classes generated by
picky-mixin could be tagged with picky-interface, enabling the is-picky? predicate:
To codify the lambda-plus-class pattern for implementing mixins, including the use of
interfaces for the domain and range of the mixin, the class system provides a mixin macro:
234
(mixin (interface-expr ...) (interface-expr ...)
decl-or-expr ...)
The first set of interface-exprs determines the domain of the mixin, and the second set
determines the range. That is, the expansion is a function that tests whether a given base class
implements the first sequence of interface-exprs and produces a class that implements
the second sequence of interface-exprs. Other requirements, such as the presence of
inherited methods in the superclass, are then checked for the class expansion of the
mixin form.
Mixins not only override methods and introduce public methods, they can also augment
methods, introduce augment-only methods, add an overrideable augmentation, and add an
augmentable override — all of the things that a class can do (see §13.5 “Final, Augment,
and Inner”).
As noted in §13.6 “Controlling the Scope of External Names”, external names can be bound
with define-member-name. This facility allows a mixin to be generalized with respect to
the methods that it defines and uses. For example, we can parameterize hungry-mixin with
respect to the external member key for eat:
To obtain a particular hungry-mixin, we must apply this function to a member key that refers
to a suitable eat method, which we can obtain using member-name-key:
Above, we apply hungry-mixin to an anonymous class that provides eat, but we can also
combine it with a class that provides chomp, instead:
235
13.8 Traits
The practical difference between mixins and traits is that two traits can be combined, even if
they include a common method and even if neither method can sensibly override the other. In
that case, the programmer must explicitly resolve the collision, usually by aliasing methods,
excluding methods, and merging a new trait that uses the aliases.
Suppose our fish% programmer wants to define two class extensions, spots and stripes,
each of which includes a get-color method. The fish’s spot color should not override
the stripe color nor vice versa; instead, a spots+stripes-fish% should combine the two
colors, which is not possible if spots and stripes are implemented as plain mixins. If,
however, spots and stripes are implemented as traits, they can be combined. First, we
alias get-color in each trait to a non-conflicting name. Second, the get-color methods
are removed from both and the traits with only aliases are merged. Finally, the new trait is
used to create a class that introduces its own get-color method based on the two aliases,
producing the desired spots+stripes extension.
One natural approach to implementing traits in Racket is as a set of mixins, with one mixin
per trait method. For example, we might attempt to define the spots and stripes traits as
follows, using association lists to represent sets:
(define spots-trait
(list (cons 'get-color
(lambda (%) (class % (super-new)
(define/public (get-color)
'black))))))
(define stripes-trait
(list (cons 'get-color
(lambda (%) (class % (super-new)
(define/public (get-color)
'red))))))
A set representation, such as the above, allows trait-sum and trait-exclude as simple
manipulations; unfortunately, it does not support the trait-alias operator. Although a
mixin can be duplicated in the association list, the mixin has a fixed method name, e.g.,
get-color, and mixins do not support a method-rename operation. To support trait-
236
alias, we must parameterize the mixins over the external method name in the same way
that eat was parameterized in §13.7.3 “Parameterized Mixins”.
(define spots-trait
(list (cons (member-name-key get-color)
(lambda (get-color-key %)
(define-member-name get-color get-color-key)
(class % (super-new)
(define/public (get-color) 'black))))))
(define ((trait->mixin T) C)
(foldr (lambda (m %) ((cdr m) (car m) %)) C T))
Thus, when the trait above is combined with other traits and then applied to a class, the use
of get-color becomes a reference to the external name get-trait-color.
This first implementation of traits supports trait-alias, and it supports a trait method that
calls itself, but it does not support trait methods that call each other. In particular, suppose
that a spot-fish’s market value depends on the color of its spots:
(define spots-trait
(list (cons (member-name-key get-color) ....)
(cons (member-name-key get-price)
(lambda (get-price %) ....
(class % ....
(define/public (get-price)
.... (get-color) ....))))))
237
In this case, the definition of spots-trait fails, because get-color is not in scope for
the get-price mixin. Indeed, depending on the order of mixin application when the trait is
applied to a class, the get-color method may not be available when get-price mixin is
applied to the class. Therefore adding an (inherit get-color) declaration to the get-
price mixin does not solve the problem.
One solution is to require the use of (send this get-color) in methods such as get-
price. This change works because send always delays the method lookup until the method
call is evaluated. The delayed lookup is more expensive than a direct call, however. Worse,
it also delays checking whether a get-color method even exists.
A second, effective, and efficient solution is to change the encoding of traits. Specifically,
we represent each method as a pair of mixins: one that introduces the method and one that
implements it. When a trait is applied to a class, all of the method-introducing mixins are
applied first. Then the method-implementing mixins can use inherit to directly access any
introduced method.
(define spots-trait
(list (list (local-member-name-key get-color)
(lambda (get-color get-price %) ....
(class % ....
(define/public (get-color) (void))))
(lambda (get-color get-price %) ....
(class % ....
(define/override (get-color) 'black))))
(list (local-member-name-key get-price)
(lambda (get-price get-color %) ....
(class % ....
(define/public (get-price) (void))))
(lambda (get-color get-price %) ....
(class % ....
(inherit get-color)
(define/override (get-price)
.... (get-color) ....))))))
With this trait encoding, trait-alias adds a new method with a new name, but it does not
change any references to the old method.
The general-purpose trait pattern is clearly too complex for a programmer to use directly,
but it is easily codified in a trait macro:
238
The ids in the optional inherit clause are available for direct reference in the method
exprs, and they must be supplied either by other traits or the base class to which the trait is
ultimately applied.
Using this form in conjunction with trait operators such as trait-sum, trait-exclude,
trait-alias, and trait->mixin, we can implement spots-trait and stripes-trait
as desired.
(define spots-trait
(trait
(define/public (get-color) 'black)
(define/public (get-price) ... (get-color) ...)))
(define stripes-trait
(trait
(define/public (get-color) 'red)))
(define spots+stripes-trait
(trait-sum
(trait-exclude (trait-alias spots-trait
get-color get-spots-color)
get-color)
(trait-exclude (trait-alias stripes-trait
get-color get-stripes-color)
get-color)
(trait
(inherit get-spots-color get-stripes-color)
(define/public (get-color)
.... (get-spots-color) .... (get-stripes-color) ....))))
As classes are values, they can flow across contract boundaries, and we may wish to protect
parts of a given class with contracts. For this, the class/c form is used. The class/c form
has many subforms, which describe two types of contracts on fields and methods: those that
affect uses via instantiated objects and those that affect subclasses.
In its simplest form, class/c protects the public fields and methods of objects instantiated
from the contracted class. There is also an object/c form that can be used to similarly
protect the public fields and methods of a particular object. Take the following definition of
animal%, which uses a public field for its size attribute:
239
(define animal%
(class object%
(super-new)
(field [size 10])
(define/public (eat food)
(set! size (+ size (get-field size food))))))
For any instantiated animal%, accessing the size field should return a positive number.
Also, if the size field is set, it should be assigned a positive number. Finally, the eat
method should receive an argument which is an object with a size field that contains a
positive number. To ensure these conditions, we will define the animal% class with an
appropriate contract:
Here we use ->m to describe the behavior of eat since we do not need to describe any
requirements for the this parameter. Now that we have our contracted class, we can see
that the contracts on both size and eat are enforced:
240
contract from: (definition animal%)
blaming: top-level
at: eval:22.0
> (define richie (new animal%))
241
There are two important caveats for external class contracts. First, external method contracts
are only enforced when the target of dynamic dispatch is the method implementation of the
contracted class, which lies within the contract boundary. Overriding that implementation,
and thus changing the target of dynamic dispatch, will mean that the contract is no longer
enforced for clients, since accessing the method no longer crosses the contract boundary.
Unlike external method contracts, external field contracts are always enforced for clients of
subclasses, since fields cannot be overridden or shadowed.
Second, these contracts do not restrict subclasses of animal% in any way. Fields and meth-
ods that are inherited and used by subclasses are not checked by these contracts, and uses of
the superclass’s methods via super are also unchecked. The following example illustrates
both caveats:
(define large-animal%
(class animal%
(super-new)
(inherit-field size)
(set! size 'large)
(define/override (eat food)
(display "Nom nom nom") (newline))))
Notice that retrieving the size field from the object elephant blames animal% for the
contract violation. This blame is correct, but unfair to the animal% class, as we have not
242
yet provided it with a method for protecting itself from subclasses. To this end we add
internal class contracts, which provide directives to subclasses for how they may access
and override features of the superclass. This distinction between external and internal class
contracts allows for weaker contracts within the class hierarchy, where invariants may be
broken internally by subclasses but should be enforced for external uses via instantiated
objects.
As a simple example of what kinds of protection are available, we provide an example aimed
at the animal% class that uses all the applicable forms:
This class contract not only ensures that objects of class animal% are protected as before, but
also ensure that subclasses of animal% only store appropriate values within the size field
and use the implementation of size from animal% appropriately. These contract forms
only affect uses within the class hierarchy, and only for method calls that cross the contract
boundary.
That means that inherit will only affect subclass uses of a method until a subclass over-
rides that method, and that override only affects calls from the superclass into a subclass’s
overriding implementation of that method. Since these only affect internal uses, the over-
ride form does not automatically enter subclasses into obligations when objects of those
classes are used. Also, use of override only makes sense, and thus can only be used, for
methods where no Beta-style augmentation has taken place. The following example shows
this difference:
(define/contract sloppy-eater%
(class/c [eat (->m edible/c edible/c)])
(begin
(define/contract glutton%
(class/c (override [eat (->m edible/c void?)]))
(class animal%
(super-new)
(inherit eat)
(define/public (gulp food-list)
(for ([f food-list])
(eat f)))))
(class glutton%
(super-new)
(inherit-field size)
(define/override (eat f)
243
(let ([food-size (get-field size f)])
(set! size (/ food-size 2))
(set-field! size f (/ food-size 2))
f)))))
In addition to the internal class contract forms shown here, there are similar forms for Beta-
style augmentable methods. The inner form describes to the subclass what is expected
from augmentations of a given method. Both augment and augride tell the subclass that
the given method is a method which has been augmented and that any calls to the method in
the subclass will dynamically dispatch to the appropriate implementation in the superclass.
Such calls will be checked according to the given contract. The two forms differ in that use of
augment signifies that subclasses can augment the given method, whereas use of augride
signifies that subclasses must override the current augmentation instead.
This means that not all forms can be used at the same time. Only one of the override,
augment, and augride forms can be used for a given method, and none of these forms
can be used if the given method has been finalized. In addition, super can be specified for
244
a given method only if augride or override can be specified. Similarly, inner can be
specified only if augment or augride can be specified.
245
14 Units (Components)
Units organize a program into separately compilable and reusable components. A unit re-
sembles a procedure in that both are first-class values that are used for abstraction. While
procedures abstract over values in expressions, units abstract over names in collections of
definitions. Just as a procedure is called to evaluate its expressions given actual arguments
for its formal parameters, a unit is invoked to evaluate its definitions given actual references
for its imported variables. Unlike a procedure, however, a unit’s imported variables can
be partially linked with the exported variables of another unit prior to invocation. Linking
merges multiple units together into a single compound unit. The compound unit itself im-
ports variables that will be propagated to unresolved imported variables in the linked units,
and re-exports some variables from the linked units for further linking.
The interface of a unit is described in terms of signatures. Each signature is defined (nor-
mally within a module) using define-signature. For example, the following signature,
placed in a "toy-factory-sig.rkt" file, describes the exports of a component that im-
plements a toy factory: By convention,
signature names
"toy-factory-sig.rkt" end with ^.
#lang racket
(define-signature toy-factory^
(build-toys ; (integer? -> (listof toy?))
repaint ; (toy? symbol? -> toy?)
toy? ; (any/c -> boolean?)
toy-color)) ; (toy? -> symbol?)
(provide toy-factory^)
(require "toy-factory-sig.rkt")
(define-unit simple-factory@
(import)
(export toy-factory^)
246
(printf "Factory started.\n")
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy 'blue)))
(provide simple-factory@)
The toy-factory^ signature also could be referenced by a unit that needs a toy factory
to implement something else. In that case, toy-factory^ would be named in an import
clause. For example, a toy store would get toys from a toy factory. (Suppose, for the sake of
an example with interesting features, that the store is willing to sell only toys in a particular
color.)
"toy-store-sig.rkt"
#lang racket
(define-signature toy-store^
(store-color ; (-> symbol?)
stock! ; (integer? -> void?)
get-inventory)) ; (-> (listof toy?))
(provide toy-store^)
"toy-store-unit.rkt"
#lang racket
(require "toy-store-sig.rkt"
"toy-factory-sig.rkt")
(define-unit toy-store@
(import toy-factory^)
(export toy-store^)
(define (maybe-repaint t)
(if (eq? (toy-color t) (store-color))
247
t
(repaint t (store-color))))
(define (stock! n)
(set! inventory
(append inventory
(map maybe-repaint
(build-toys n)))))
(provide toy-store@)
The simple-factory@ unit has no imports, so it can be invoked directly using invoke-
unit:
The invoke-unit form does not make the body definitions available, however, so we can-
not build any toys with this factory. The define-values/invoke-unit form binds the
identifiers of a signature to the values supplied by a unit (to be invoked) that implements the
signature:
> (build-toys 3)
(list (toy 'blue) (toy 'blue) (toy 'blue))
248
Now that the identifiers in toy-factory^ are defined, we can also invoke toy-store@,
which imports toy-factory^ to produce toy-store^:
> (get-inventory)
'()
> (stock! 2)
> (get-inventory)
(list (toy 'green) (toy 'green))
We can make our toy economy more efficient by having toy factories that cooperate with
stores, creating toys that do not have to be repainted. Instead, the toys are always created
using the store’s color, which the factory gets by importing toy-store^:
"store-specific-factory-unit.rkt"
#lang racket
(require "toy-store-sig.rkt"
"toy-factory-sig.rkt")
(define-unit store-specific-factory@
(import toy-store^)
(export toy-factory^)
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy)))
249
(provide store-specific-factory@)
The solution is to link the units together, and then we can invoke the combined units. The
define-compound-unit/infer form links any number of units to form a combined unit.
It can propagate imports and exports from the linked units, and it can satisfy each unit’s
imports using the exports of other linked units.
> (require "toy-factory-sig.rkt")
The overall result above is a unit toy-store+factory@ that exports both toy-factory^
and toy-store^. The connection between store-specific-factory@ and toy-store@
is inferred from the signatures that each imports and exports.
> (stock! 2)
> (get-inventory)
(list (toy) (toy))
> (map toy-color (get-inventory))
'(green green)
The define-unit form combines define with a unit form, similar to the way that (de-
fine (f x) ....) combines define followed by an identifier with an implicit lambda.
250
Expanding the shorthand, the definition of toy-store@ could almost be written as
(define toy-store@
(unit
(import toy-factory^)
(export toy-store^)
A difference between this expansion and define-unit is that the imports and exports of
toy-store@ cannot be inferred. That is, besides combining define and unit, define-
unit attaches static information to the defined identifier so that its signature information is
available statically to define-values/invoke-unit/infer and other forms.
Despite the drawback of losing static signature information, unit can be useful in combina-
tion with other forms that work with first-class values. For example, we could wrap a unit
that creates a toy store in a lambda to supply the store’s color:
"toy-store-maker.rkt"
#lang racket
(require "toy-store-sig.rkt"
"toy-factory-sig.rkt")
(define toy-store@-maker
(lambda (the-color)
(unit
(import toy-factory^)
(export toy-store^)
(define (maybe-repaint t)
(if (eq? (toy-color t) (store-color))
t
(repaint t (store-color))))
(define (stock! n)
(set! inventory
251
(append inventory
(map maybe-repaint
(build-toys n)))))
(provide toy-store@-maker)
> (stock! 2)
> (get-inventory)
(list (toy 'purple) (toy 'purple))
252
This compound-unit form packs a lot of information into one place. The left-hand-
side TF and TS in the link clause are binding identifiers. The identifier TF is essentially
bound to the elements of toy-factory^ as implemented by store-specific-factory@.
The identifier TS is similarly bound to the elements of toy-store^ as implemented by
toy-store@. Meanwhile, the elements bound to TS are supplied as imports for store-
specific-factory@, since TS follows store-specific-factory@. The elements bound
to TF are similarly supplied to toy-store@. Finally, (export TF TS) indicates that the
elements bound to TF and TS are exported from the compound unit.
#lang racket/signature
The signature toy-factory^ is automatically provided from the module, inferred from the
filename "toy-factory-sig.rkt" by replacing the "-sig.rkt" suffix with ^.
#lang racket/unit
(require "toy-factory-sig.rkt")
(import)
(export toy-factory^)
253
(printf "Factory started.\n")
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy 'blue)))
The unit simple-factory@ is automatically provided from the module, inferred from the
filename "simple-factory-unit.rkt" by replacing the "-unit.rkt" suffix with @.
There are a couple of ways of protecting units with contracts. One way is useful when
writing new signatures, and the other handles the case when a unit must conform to an
already existing signature.
When contracts are added to a signature, then all units which implement that signature are
protected by those contracts. The following version of the toy-factory^ signature adds
the contracts previously written in comments:
"contracted-toy-factory-sig.rkt"
#lang racket
(define-signature contracted-toy-factory^
((contracted
[build-toys (-> integer? (listof toy?))]
[repaint (-> toy? symbol? toy?)]
[toy? (-> any/c boolean?)]
[toy-color (-> toy? symbol?)])))
(provide contracted-toy-factory^)
Now we take the previous implementation of simple-factory@ and implement this version
of toy-factory^ instead:
"contracted-simple-factory-unit.rkt"
254
#lang racket
(require "contracted-toy-factory-sig.rkt")
(define-unit contracted-simple-factory@
(import)
(export contracted-toy-factory^)
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy 'blue)))
(provide contracted-simple-factory@)
As before, we can invoke our new unit and bind the exports so that we can use them. This
time, however, misusing the exports causes the appropriate contract errors.
> (require "contracted-simple-factory-unit.rkt")
> (build-toys 3)
(list (toy 'blue) (toy 'blue) (toy 'blue))
> (build-toys #f)
build-toys: contract violation
expected: integer?
given: #f
in: the 1st argument of
(-> integer? (listof toy?))
contract from:
(unit contracted-simple-factory@)
blaming: top-level
at: eval:34.0
> (repaint 3 'blue)
repaint: contract violation
expected: toy?
given: 3
in: the 1st argument of
255
(-> toy? symbol? toy?)
contract from:
(unit contracted-simple-factory@)
blaming: top-level
at: eval:34.0
However, sometimes we may have a unit that must conform to an already existing signature
that is not contracted. In this case, we can create a unit contract with unit/c or use the
define-unit/contract form, which defines a unit which has been wrapped with a unit
contract.
For example, here’s a version of toy-factory@ which still implements the regular toy-
factory^, but whose exports have been protected with an appropriate unit contract.
"wrapped-simple-factory-unit.rkt"
#lang racket
(require "toy-factory-sig.rkt")
(define-unit/contract wrapped-simple-factory@
(import)
(export (toy-factory^
[build-toys (-> integer? (listof toy?))]
[repaint (-> toy? symbol? toy?)]
[toy? (-> any/c boolean?)]
[toy-color (-> toy? symbol?)]))
(define (build-toys n)
(for/list ([i (in-range n)])
(make-toy 'blue)))
(provide wrapped-simple-factory@)
256
> (define-values/invoke-unit/infer wrapped-simple-factory@)
Factory started.
> (build-toys 3)
(list (toy 'blue) (toy 'blue) (toy 'blue))
> (build-toys #f)
wrapped-simple-factory@: contract violation
expected: integer?
given: #f
in: the 1st argument of
...
(unit/c
(import)
(export (toy-factory^
(build-toys
(-> integer? (listof toy?)))
(repaint (-> toy? symbol? toy?))
(toy? (-> any/c boolean?))
(toy-color (-> toy? symbol?)))))
contract from:
(unit wrapped-simple-factory@)
blaming: top-level
at: <collects>/racket/unit.rkt
> (repaint 3 'blue)
wrapped-simple-factory@: contract violation
expected: toy?
given: 3
in: the 1st argument of
...
(unit/c
(import)
(export (toy-factory^
(build-toys
(-> integer? (listof toy?)))
(repaint (-> toy? symbol? toy?))
(toy? (-> any/c boolean?))
(toy-color (-> toy? symbol?)))))
contract from:
(unit wrapped-simple-factory@)
blaming: top-level
at: <collects>/racket/unit.rkt
257
14.7 unit versus module
• The module form is primarily for managing a universal namespace. For example, it
allows a code fragment to refer specifically to the car operation from racket/base—
the one that extracts the first element of an instance of the built-in pair datatype—as
opposed to any number of other functions with the name car. In other words, the
module construct lets you refer to the binding that you want.
• The unit form is for parameterizing a code fragment with respect to most any kind
of run-time value. For example, it allows a code fragment to work with a car func-
tion that accepts a single argument, where the specific function is determined later by
linking the fragment to another. In other words, the unit construct lets you refer to a
binding that meets some specification.
The lambda and class forms, among others, also allow paremetrization of code with re-
spect to values that are chosen later. In principle, any of those could be implemented in terms
of any of the others. In practice, each form offers certain conveniences—such as allowing
overriding of methods or especially simple application to values—that make them suitable
for different purposes.
The module form is more fundamental than the others, in a sense. After all, a program
fragment cannot reliably refer to a lambda, class, or unit form without the namespace
management provided by module. At the same time, because namespace management
is closely related to separate expansion and compilation, module boundaries end up as
separate-compilation boundaries in a way that prohibits mutual dependencies among frag-
ments. For similar reasons, module does not separate interface from implementation.
Use unit when module by itself almost works, but when separately compiled pieces must
refer to each other, or when you want a stronger separation between interface (i.e., the parts
that need to be known at expansion and compilation time) and implementation (i.e., the run-
time parts). More generally, use unit when you need to parameterize code over functions,
datatypes, and classes, and when the parameterized code itself provides definitions to be
linked with other parameterized code.
258
15 Reflection and Dynamic Evaluation
Racket is a dynamic language. It offers numerous facilities for loading, compiling, and even
constructing new code at run time.
15.1 eval
This example will
not work within a
The eval function takes a representation of an expression or definition (as a “quoted” form module or in
DrRacket’s
or syntax object) and evaluates it: definitions window,
but it will work in
> (eval '(+ 1 2)) the interactions
3 window, for reasons
that are explained
by the end of
The power of eval is that an expression can be constructed dynamically: §15.1.2
“Namespaces”.
> (define (eval-formula formula)
(eval `(let ([x 2]
[y 3])
,formula)))
Of course, if we just wanted to evaluate expressions with given values for x and y, we do not
need eval. A more direct approach is to use first-class functions:
Also, eval is often used directly or indirectly on whole modules. For example, a program
might load a module on demand using dynamic-require, which is essentially a wrapper
around eval to dynamically load the module code.
259
15.1.1 Local Scopes
The eval function cannot see local bindings in the context where it is called. For example,
calling eval inside an unquoted let form to evaluate a formula does not make values visible
for x and y:
The eval function cannot see the x and y bindings precisely because it is a function, and
Racket is a lexically scoped language. Imagine if eval were implemented as
(define (eval x)
(eval-expanded (macro-expand x)))
then at the point when eval-expanded is called, the most recent binding of x is to the
expression to evaluate, not the let binding in broken-eval-formula. Lexical scope pre-
vents such confusing and fragile behavior, and consequently prevents eval from seeing local
bindings in the context where it is called.
You might imagine that even though eval cannot see the local bindings in broken-eval-
formula, there must actually be a data structure mapping x to 2 and y to 3, and you would
like a way to get that data structure. In fact, no such data structure exists; the compiler is free
to replace every use of x with 2 at compile time, so that the local binding of x does not exist
in any concrete sense at run-time. Even when variables cannot be eliminated by constant-
folding, normally the names of the variables can be eliminated, and the data structures that
hold local values do not resemble a mapping from names to values.
15.1.2 Namespaces
Since eval cannot see the bindings from the context where it is called, another mechanism
is needed to determine dynamically available bindings. A namespace is a first-class value
that encapsulates the bindings available for dynamic evaluation. Informally, the term
namespace is
Some functions, such as eval, accept an optional namespace argument. More often, the sometimes used
interchangeably
namespace used by a dynamic operation is the current namespace as determined by the with environment or
current-namespace parameter. scope. In Racket,
the term namespace
has the more
specific, dynamic
260 meaning given
above, and it should
not be confused
with static lexical
concepts.
When eval is used in a REPL, the current namespace is the one that the REPL uses for
evaluating expressions. That’s why the following interaction successfully accesses x via
eval:
> (define x 3)
In contrast, try the following a simple module and running in directly in DrRacket or sup-
plying the file as a command-line argument to racket:
#lang racket
This fails because the initial current namespace is empty. When you run racket in inter-
active mode (see §19.1.1 “Interactive Mode”), the initial namespace is initialized with the
exports of the racket module, but when you run a module directly, the initial namespace
starts empty.
In general, it’s a bad idea to use eval with whatever namespace happens to be installed.
Instead, create a namespace explicitly and install it for the call to eval:
#lang racket
(define ns (make-base-namespace))
(eval '(cons 1 2) ns) ; works
The make-base-namespace function creates a namespace that is initialized with the ex-
ports of racket/base. The later section §15.2 “Manipulating Namespaces” provides more
information on creating and configuring namespaces.
As with let bindings, lexical scope means that eval cannot automatically see the definitions
of a module in which it is called. Unlike let bindings, however, Racket provides a way to
reflect a module into a namespace.
The module->namespace function takes a quoted module path and produces a namespace
for evaluating expressions and definitions as if they appeared in the module body:
261
> (require 'm)
#lang racket
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(define x 1)
(define y 2)
• A mapping from identifiers to bindings. For example, a namespace might map the
identifier lambda to the lambda form. An “empty” namespace is one that maps every
identifier to an uninitialized top-level variable.
• A mapping from module names to module declarations and instances.
The first mapping is used for evaluating expressions in a top-level context, as in (eval
'(lambda (x) (+ x 1))). The second mapping is used, for example, by dynamic-
require to locate a module. The call (eval '(require racket/base)) normally uses
both pieces: the identifier mapping determines the binding of require; if it turns out to
mean require, then the module mapping is used to locate the racket/base module.
From the perspective of the core Racket run-time system, all evaluation is reflective. Execu-
tion starts with an initial namespace that contains a few primitive modules, and that is further
262
populated by loading files and modules as specified on the command line or as supplied in
the REPL. Top-level require and define forms adjusts the identifier mapping, and module
declarations (typically loaded on demand for a require form) adjust the module mapping.
The function make-empty-namespace creates a new, empty namespace. Since the names-
pace is truly empty, it cannot at first be used to evaluate any top-level expression—not even
(require racket). In particular,
fails, because the namespace does not include the primitive modules on which racket is
built.
To make a namespace useful, some modules must be attached from an existing namespace.
Attaching a module adjusts the mapping of module names to instances by transitively copy-
ing entries (the module and all its imports) from an existing namespace’s mapping. Nor-
mally, instead of just attaching the primitive modules—whose names and organization are
subject to change—a higher-level module is attached, such as racket or racket/base.
Note that the parameterize of current-namespace does not affect the meaning of iden-
tifiers like namespace-require within the parameterize body. Those identifiers obtain
their meaning from the enclosing context (probably a module). Only expressions that are
dynamic with respect to this code, such as the content of loaded files, are affected by the
parameterize.
263
Another subtle point in the above example is the use of (namespace-require 'my-dsl)
instead of (eval '(require my-dsl)). The latter would not work, because eval needs
to obtain a meaning for require in the namespace, and the namespace’s identifier mapping
is initially empty. The namespace-require function, in contrast, directly imports the given
module into the current namespace. Starting with (namespace-require 'racket/base)
would introduce a binding for require and make a subsequent (eval '(require my-
dsl)) work. The above is better, not only because it is more compact, but also because it
avoids introducing bindings that are not part of the domain-specific languages.
Modules not attached to a new namespace will be loaded and instantiated afresh if they are
demanded by evaluation. For example, racket/base does not include racket/class, and
loading racket/class again will create a distinct class datatype:
> (require racket/class)
For cases when dynamically loaded code needs to share more code and data with its context,
use the namespace-attach-module function. The first argument to namespace-attach-
module is a source namespace from which to draw a module instance; in some cases, the
current namespace is known to include the module that needs to be shared:
> (require racket/class)
> (class?
(let ([ns (make-base-empty-namespace)])
(namespace-attach-module (current-namespace)
'racket/class
ns)
(parameterize ([current-namespace ns])
(namespace-require 'racket/class) ; uses attached
(eval 'object%))))
#t
264
#lang racket/base
(require racket/class)
(define-namespace-anchor a)
The anchor bound by namespace-attach-module connects the run time of a module with
the namespace in which a module is loaded (which might differ from the current namespace).
In the above example, since the enclosing module requires racket/class, the namespace
produced by namespace-anchor->empty-namespace certainly contains an instance of
racket/class. Moreover, that instance is the same as the one imported into the module,
so the class datatype is shared.
Historically, Lisp implementations did not offer module systems. Instead, large programs
were built by essentially scripting the REPL to evaluate program fragments in a particular
order. While REPL scripting turns out to be a bad way to structure programs and libraries, it
is still sometimes a useful capability. Describing a
program via load
The load function runs a REPL script by reading S-expressions from a file, one by one, interacts especially
badly with
and passing them to eval. If a file "place.rkts" contains macro-defined
(define city "Salt Lake City") language extensions
[Flatt02].
(define state "Utah")
(printf "∼a, ∼a\n" city state)
> city
"Salt Lake City"
Since load uses eval, however, a module like the following generally will not work—for
the same reasons described in §15.1.2 “Namespaces”:
265
#lang racket
(load "here.rkts")
The current namespace for evaluating the content of "here.rkts" is likely to be empty; in
any case, you cannot get there from "here.rkts". Also, any definitions in "here.rkts"
will not become visible for use within the module; after all, the load happens dynamically,
while references to identifiers within the module are resolved lexically, and therefore stati-
cally.
Unlike eval, load does not accept a namespace argument. To supply a namespace to load,
set the current-namespace parameter. The following example evaluates the expressions
in "here.rkts" using the bindings of the racket/base module:
#lang racket
You can even use namespace-anchor->namespace to make the bindings of the enclosing
module accessible for dynamic evaluation. In the following example, when "here.rkts"
is loaded, it can refer to there as well as the bindings of racket:
#lang racket
(define-namespace-anchor a)
(parameterize ([current-namespace (namespace-anchor-
>namespace a)])
(load "here.rkts"))
Still, if "here.rkts" defines any identifiers, the definitions cannot be directly (i.e., stati-
cally) referenced by in the enclosing module.
266
then running
#lang racket/load
(load "here.rkts")
(go!)
(printf "∼a\n" here)
prints “Utopia”.
Drawbacks of using racket/load include reduced error checking, tool support, and perfor-
mance. For example, with the program
#lang racket/load
(define good 5)
(printf "running\n")
good
bad
DrRacket’s Check Syntax tool cannot tell that the second good is a reference to the first, and
the unbound reference to bad is reported only at run time instead of rejected syntactically.
267
16 Macros
A macro is a syntactic form with an associated transformer that expands the original form
into existing forms. To put it another way, a macro is an extension to the Racket compiler.
Most of the syntactic forms of racket/base and racket are actually macros that expand
into a small set of core constructs.
Like many languages, Racket provides pattern-based macros that make simple transforma-
tions easy to implement and reliable to use. Racket also supports arbitrary macro transform-
ers that are implemented in Racket—or in a macro-extended variant of Racket.
A pattern-based macro replaces any code that matches a pattern to an expansion that uses
parts of the original syntax that match parts of the pattern.
16.1.1 define-syntax-rule
As a running example, consider the swap macro, which swaps the values stored in two
variables. It can be implemented using define-syntax-rule as follows: The macro is
“un-Rackety” in the
(define-syntax-rule (swap x y) sense that it
(let ([tmp x]) involves side effects
on variables—but
(set! x y) the point of macros
(set! y tmp))) is to let you add
syntactic forms that
some other
The define-syntax-rule form binds a macro that matches a single pattern. The pattern language designer
might not approve.
must always start with an open parenthesis followed by an identifier, which is swap in this
case. After the initial identifier, other identifiers are macro pattern variables that can match
anything in a use of the macro. Thus, this macro matches the form (swap form1 form2 )
for any form_1 and form_2 . Macro pattern
variables similar to
After the pattern in define-syntax-rule is the template. The template is used in place of pattern variables for
match. See §12
a form that matches the pattern, except that each instance of a pattern variable in the template “Pattern Matching”.
is replaced with the part of the macro use the pattern variable matched. For example, in
268
the pattern variable x matches first and y matches last, so that the expansion is
Suppose that we use the swap macro to swap variables named tmp and other:
(let ([tmp 5]
[other 6])
(swap tmp other)
(list tmp other))
The result of the above expression should be (6 5). The naive expansion of this use of
swap, however, is
(let ([tmp 5]
[other 6])
(let ([tmp tmp])
(set! tmp other)
(set! other tmp))
(list tmp other))
whose result is (5 6). The problem is that the naive expansion confuses the tmp in the
context where swap is used with the tmp that is in the macro template.
Racket doesn’t produce the naive expansion for the above use of swap. Instead, it produces
(let ([tmp 5]
[other 6])
(let ([tmp_1 tmp])
(set! tmp other)
(set! other tmp_1))
(list tmp other))
(let ([set! 5]
[other 6])
(swap set! other)
(list set! other))
269
the expansion is
(let ([set!_1 5]
[other 6])
(let ([tmp_1 set!_1])
(set! set!_1 other)
(set! other tmp_1))
(list set!_1 other))
so that the local set! binding doesn’t interfere with the assignments introduced by the macro
template.
The define-syntax-rule form binds a macro that matches a single pattern, but Racket’s
macro system supports transformers that match multiple patterns starting with the same iden-
tifier. To write such macros, the programmer must use the more general define-syntax
form along with the syntax-rules transformer form:
(define-syntax id
(syntax-rules (literal-id ...)
[pattern template ]
...))
The
define-syntax-rule
For example, suppose we would like a rotate macro that generalizes swap to work on either form is itself a
two or three identifiers, so that macro that expands
into
(let ([red 1] [green 2] [blue 3]) define-syntax
(rotate red green) ; swaps with a
syntax-rules
(rotate red green blue) ; rotates left form that contains
(list red green blue)) only one pattern
and template.
270
The expression (rotate red green) matches the first pattern in the syntax-rules form,
so it expands to (swap red green). The expression (rotate a b c) matches the second
pattern, so it expands to (begin (swap red green) (swap green blue)).
A better rotate macro would allow any number of identifiers, instead of just two or three.
To match a use of rotate with any number of identifiers, we need a pattern form that has
something like a Kleene star. In a Racket macro pattern, a star is written as ....
To implement rotate with ..., we need a base case to handle a single identifier, and an
inductive case to handle more than one identifier:
(define-syntax rotate
(syntax-rules ()
[(rotate a) (void)]
[(rotate a b c ...) (begin
(swap a b)
(rotate b c ...))]))
When a pattern variable like c is followed by ... in a pattern, then it must be followed by
... in a template, too. The pattern variable effectively matches a sequence of zero or more
forms, and it is replaced in the template by the same sequence.
Both versions of rotate so far are a bit inefficient, since pairwise swapping keeps moving
the value from the first variable into every variable in the sequence until it arrives at the last
one. A more efficient rotate would move the first value directly to the last variable. We
can use ... patterns to implement the more efficient variant using a helper macro:
(define-syntax rotate
(syntax-rules ()
[(rotate a c ...)
(shift-to (c ... a) (a c ...))]))
(define-syntax shift-to
(syntax-rules ()
[(shift-to (from0 from ...) (to0 to ...))
(let ([tmp from0])
(set! to from) ...
(set! to0 tmp))]))
In the shift-to macro, ... in the template follows (set! to from), which causes the
(set! to from) expression to be duplicated as many times as necessary to use each iden-
tifier matched in the to and from sequences. (The number of to and from matches must be
the same, otherwise the macro expansion fails with an error.)
271
16.1.5 Identifier Macros
Given our macro definitions, the swap or rotate identifiers must be used after an open
parenthesis, otherwise a syntax error is reported:
> (+ swap 3)
eval:2:0: swap: bad syntax
in: swap
An identifier macro works in any expression. For example, we can define clock as an iden-
tifier macro that expands to (get-clock), so (+ clock 3) would expand to (+ (get-
clock) 3). An identifier macro also cooperates with set!, and we can define clock so
that (set! clock 3) expands to (put-clock! 3).
The syntax-id-rules form is like syntax-rules, but it creates a transformer that acts as
an identifier macro:
(define-syntax id
(syntax-id-rules (literal-id ...)
[pattern template ]
...))
Unlike a syntax-rules form, the pattern s are not required to start with an open paren-
thesis. In addition, syntax-id-rules cooperates specially with set!, so that set! invokes
the macro when id is the target of an assignment; consequently, set! is typically used as a
literal with syntax-id-rules to match such uses of set!.
(define-syntax clock
(syntax-id-rules (set!)
[(set! clock e) (put-clock! e)]
[(clock a ...) ((get-clock) a ...)]
[clock (get-clock)]))
The (clock a ...) pattern is needed because, when an identifier macro is used after an
open parenthesis, the macro transformer is given the whole form, like with a non-identifier
macro. Put another way, the syntax-rules form is essentially a special case of the
syntax-id-rules form with errors in the set! and lone-identifier cases.
272
16.1.6 Macro-Generating Macros
Suppose that we have many identifiers like clock that we’d like to redirect to accessor and
mutator functions like get-clock and put-clock!. We’d like to be able to just write
We can use pattern-matching macros to add a form to Racket for defining first-order call-by-
reference functions. When a call-by-reference function body mutates its formal argument,
the mutation applies to variables that are supplied as actual arguments in a call to the func-
tion.
For example, if define-cbr is like define except that it defines a call-by-reference func-
tion, then
(define-cbr (f a b)
(swap a b))
produces (2 1).
We will implement call-by-reference functions by having function calls supply accessor and
mutators for the arguments, instead of supplying argument values directly. In particular, for
the function f above, we’ll generate
273
(define (do-f get-a get-b put-a! put-b!)
(define-get/put-id a get-a put-a!)
(define-get/put-id b get-b put-b!)
(swap a b))
(do-f (lambda () x)
(lambda () y)
(lambda (v) (set! x v))
(lambda (v) (set! y v)))
Clearly, then define-cbr is a macro-generating macro, which binds f to a macro that ex-
pands to a call of do-f. That is, (define-cbr (f a b) (swap a b)) needs to generate
the definition
(define-syntax f
(syntax-rules ()
[(id actual ...)
(do-f (lambda () actual)
...
(lambda (v)
(set! actual v))
...)]))
At the same time, define-cbr needs to define do-f using the body of f, this second part
is slightly more complex, so we defer most it to a define-for-cbr helper module, which
lets us write define-cbr easily enough:
274
(define-for-cbr do-f (a b) () (swap a b))
to the function definition do-f above. Most of the work is generating a define-get/put-
id declaration for each argument, a and b, and putting them before the body. Normally,
that’s an easy task for ... in a pattern and template, but this time there’s a catch: we need
to generate the names get-a and put-a! as well as get-b and put-b!, and the pattern
language provides no way to synthesize identifiers based on existing identifiers.
As it turns out, lexical scope gives us a way around this problem. The trick is to iterate
expansions of define-for-cbr once for each argument in the function, and that’s why
define-cbr starts with an apparently useless () after the argument list. We need to keep
track of all the arguments seen so far and the get and put names generated for each, in
addition to the arguments left to process. After we’ve processed all the identifiers, then we
have all the names we need.
(define-syntax define-for-cbr
(syntax-rules ()
[(define-for-cbr do-f (id0 id ...)
(gens ...) body)
(define-for-cbr do-f (id ...)
(gens ... (id0 get put)) body)]
[(define-for-cbr do-f ()
((id get put) ...) body)
(define (do-f get ... put ...)
(define-get/put-id id get put) ...
body)]))
(define-for-cbr do-f (a b)
() (swap a b))
=> (define-for-cbr do-f (b)
([a get_1 put_1]) (swap a b))
=> (define-for-cbr do-f ()
([a get_1 put_1] [b get_2 put_2]) (swap a b))
=> (define (do-f get_1 get_2 put_1 put_2)
(define-get/put-id a get_1 put_1)
(define-get/put-id b get_2 put_2)
(swap a b))
The “subscripts” on get_1, get_2, put_1, and put_2 are inserted by the macro expander
to preserve lexical scope, since the get generated by each iteration of define-for-cbr
should not bind the get generated by a different iteration. In other words, we are essentially
275
tricking the macro expander into generating fresh names for us, but the technique illustrates
some of the surprising power of pattern-based macros with automatic lexical scope.
To summarize, then, we can add call-by-reference functions to Racket with just three small
pattern-based macros: define-cbr, define-for-cbr, and define-get/put-id.
The define-syntax form creates a transformer binding for an identifier, which is a binding
that can be used at compile time while expanding expressions to be evaluated at run time.
The compile-time value associated with a transformer binding can be anything; if it is a
procedure of one argument, then the binding is used as a macro, and the procedure is the
macro transformer.
The syntax-rules and syntax-id-rules forms are macros that expand to procedure
forms. For example, if you evaluate a syntax-rules form directly (instead of placing on
the right-hand of a define-syntax form), the result is a procedure:
Instead of using syntax-rules, you can write your own macro transformer procedure di-
rectly using lambda. The argument to the procedure is a value that represents the source
form, and the result of the procedure must be a value that represents the replacement form.
The input and output of a macro transformer (i.e., source and replacement forms) are repre-
sented as syntax objects. A syntax object contains symbols, lists, and constant values (such
as numbers) that essentially correspond to the quoted form of the expression. For example,
a representation of the expression (+ 1 2) contains the symbol '+ and the numbers 1 and 2,
all in a list. In addition to this quoted content, a syntax object associates source-location and
lexical-binding information with each part of the form. The source-location information is
276
used when reporting syntax errors (for example), and the lexical-biding information allows
the macro system to maintain lexical scope. To accommodate this extra information, the
represention of the expression (+ 1 2) is not merely '(+ 1 2), but a packaging of '(+ 1
2) into a syntax object.
In the same way that ' abbreviates quote, #' abbreviates syntax:
> #'(+ 1 2)
#<syntax:1:0 (+ 1 2)>
A syntax object that contains just a symbol is an identifier syntax object. Racket provides
some additional operations specific to identifier syntax objects, including the identifier?
operation to detect identifiers. Most notably, free-identifier=? determines whether two
identifiers refer to the same binding:
> (identifier? #'car)
#t
> (identifier? #'(+ 1 2))
#f
> (free-identifier=? #'car #'cdr)
#f
> (free-identifier=? #'car #'car)
#t
> (require (only-in racket/base [car also-car]))
The last example above, in particular, illustrates how syntax objects preserve lexical-context
information.
To see the lists, symbols, numbers, etc. within a syntax object, use syntax->datum:
> (syntax->datum #'(+ 1 2))
'(+ 1 2)
277
> (syntax-e #'(+ 1 2))
'(#<syntax:1:0 +> #<syntax:1:0 1> #<syntax:1:0 2>)
The syntax-e function always leaves syntax-object wrappers around sub-forms that are
represented via symbols, numbers, and other literal values. The only time it unwraps extra
sub-forms is when unwrapping a pair, in which case the cdr of the pair may be recursively
unwrapped, depending on how the syntax object was constructed.
In the above example, the lexical context of #'lex is used for the new syntax object, while
the source location of #'srcloc is used.
When the second (i.e., the “datum”) argument to datum->syntax includes syntax objects,
those syntax objects are preserved intact in the result. That is, deconstructing the result with
syntax-e eventually produces the syntax objects that were given to datum->syntax.
The syntax-case form lets you mix pattern matching, template construction, and arbitrary
expressions:
Unlike syntax-rules, the syntax-case form does not produce a procedure. Instead,
it starts with a stx-expr expression that determines the syntax object to match against
the pattern s. Also, each syntax-case clause has a pattern and expr , instead of a
pattern and template . Within an expr , the syntax form—usually abbreviated with
278
#'—shifts into template-construction mode; if the expr of a clause starts with #', then we
have something like a syntax-rules form:
> (syntax->datum
(syntax-case #'(+ 1 2) ()
[(op n1 n2) #'(- n1 n2)]))
'(- 1 2)
One advantage of using syntax-case is that we can provide better error reporting for swap.
For example, with the define-syntax-rule definition of swap, then (swap x 2) pro-
duces a syntax error in terms of set!, because 2 is not an identifier. We can refine our
syntax-case implementation of swap to explicitly check the sub-forms:
(define-syntax swap
(lambda (stx)
(syntax-case stx ()
[(swap x y)
(if (and (identifier? #'x)
(identifier? #'y))
#'(let ([tmp x])
(set! x y)
(set! y tmp))
(raise-syntax-error #f
"not an identifier"
stx
(if (identifier? #'x)
#'y
#'x)))])))
With this definition, (swap x 2) provides a syntax error originating from swap instead of
set!.
In the above definition of swap, #'x and #'y are templates, even though they are not used
as the result of the macro transformer. This example illustrates how templates can be used to
access pieces of the input syntax, in this case for checking the form of the pieces. Also, the
match for #'x or #'y is used in the call to raise-syntax-error, so that the syntax-error
message can point directly to the source location of the non-identifier.
279
16.2.3 with-syntax and generate-temporaries
Since syntax-case lets us compute with arbitrary Racket expression, we can more simply
solve a problem that we had in writing define-for-cbr (see §16.1.7 “Extended Example:
Call-by-Reference Functions”), where we needed to generate a set of names based on a
sequence id ...:
Now we need an expression in place of .... that generates as many identifiers as there
are id matches in the original pattern. Since this is a common task, Racket provides a
helper function, generate-temporaries, that takes a sequence of identifiers and returns a
sequence of generated identifiers:
This way of generating identifiers is normally easier to think about than tricking the macro
expander into generating names with purely pattern-based macros.
280
In general, the right-hand side of a with-syntax binding is a pattern, just like in syntax-
case. In fact, a with-syntax form is just a syntax-case form turned partially inside-out.
As sets of macros get more complicated, you might want to write your own helper functions,
like generate-temporaries. For example, to provide good syntax-error messsage, swap,
rotate, and define-cbr all should check that certain sub-forms in the source form are
identifiers. We could use a check-ids to perform this checking everywhere:
The check-ids function can use the syntax->list function to convert a syntax-object
wrapping a list into a list of syntax objects:
If you define swap and check-ids in this way, however, it doesn’t work:
281
The problem is that check-ids is defined as a run-time expression, but swap is trying to
use it at compile time. In interactive mode, compile time and run time are interleaved,
but they are not interleaved within the body of a module, and they are not interleaved or
across modules that are compiled ahead-of-time. To help make all of these modes treat code
consistently, Racket separates the binding spaces for different phases.
To define a check-ids function that can be referenced at compile time, use begin-for-
syntax:
(begin-for-syntax
(define (check-ids stx forms)
(for-each
(lambda (form)
(unless (identifier? form)
(raise-syntax-error #f
"not an identifier"
stx
form)))
(syntax->list forms))))
When organizing a program into modules, you may want to put helper functions in one
module to be used by macros that reside on other modules. In that case, you can write the
helper function using define:
"utils.rkt"
#lang racket
(provide check-ids)
282
Then, in the module that implements macros, import the helper function using (require
(for-syntax "utils.rkt")) instead of (require "utils.rkt"):
#lang racket
Since modules are separately compiled and cannot have circular dependencies, the
"utils.rkt" module’s run-time body can be compiled before the compiling the module
that implements swap. Thus, the run-time definitions in "utils.rkt" can be used to im-
plement swap, as long as they are explicitly shifted into compile time by (require (for-
syntax ....)).
The racket/base module, in contrast, exports those bindings only in the run-time phase.
If you change the module above that defines swap so that it uses the racket/base lan-
guage instead of racket, then it no longer works. Adding (require (for-syntax
racket/base)) imports syntax-case and more into the compile-time phase, so that the
module works again.
Suppose that define-syntax is used to define a local macro in the right-hand side of
a define-syntax form. In that case, the right-hand side of the inner define-syntax
is in the meta-compile phase level, also known as phase level 2. To import syntax-
case into that phase level, you would have to use (require (for-syntax (for-syntax
racket/base))) or, equivalently, (require (for-meta 2 racket/base)). For exam-
ple,
#lang racket/base
(require ;; This provides the bindings for the definition
;; of shell-game.
(for-syntax racket/base)
283
(for-syntax (for-syntax racket/base)))
(syntax-case stx ()
[(_ a b c)
(let ([a #'a] [b #'b] [c #'c])
(when (= 0 (random 2)) (swap a b))
(when (= 0 (random 2)) (swap b c))
(when (= 0 (random 2)) (swap a c))
#`(list #,a #,b #,c))]))
(shell-game 3 4 5)
(shell-game 3 4 5)
(shell-game 3 4 5)
Negative phase levels also exist. If a macro uses a helper function that is imported for-
syntax, and if the helper function returns syntax-object constants generated by syntax,
then identifiers in the syntax will need bindings at phase level -1, also known as the template
phase level, to have any binding at the run-time phase level relative to the module that defines
the macro.
Imagine starting two Racket processes for this purpose. If you ignore inter-process commu-
nication channels like sockets and files, the processes will have no way to share anything
other than the text that is piped from the standard output of one process into the standard
input of the other. Similarly, Racket effectively allows multiple invocations of a module to
exist in the same process but separated by phase. Racket enforces separation of such phases,
where different phases cannot communicate in any way other than via the protocol of macro
expansion, where the output of one phases is the code used in the next.
284
Every binding of an identifier exists in a particular phase. The link between a binding and
its phase is represented by an integer phase level. Phase level 0 is the phase used for “plain”
(or “runtime”) definitions, so
(define age 5)
adds a binding for age into phase level 0. The identifier age can be defined at a higher phase
level using begin-for-syntax:
(begin-for-syntax
(define age 5))
With a single begin-for-syntax wrapper, age is defined at phase level 1. We can easily
mix these two definitions in the same module or in a top-level namespace, and there is no
clash between the two ages that are defined at different phase levels:
> (begin-for-syntax
(define age 9))
The age binding at phase level 0 has a value of 3, and the age binding at phase level 1 has a
value of 9.
#'age
is a syntax object that represents the age binding—but since there are two ages (one at phase
level 0 and one at phase level 1), which one does it capture? In fact, Racket imbues #'age
with lexical information for all phase levels, so the answer is that #'age captures both.
The relevant binding of age captured by #'age is determined when #'age is eventually
used. As an example, we bind #'age to a pattern variable so we can use it in a template, and
then we evalutae the template: We use eval here
to demonstrate
> (eval (with-syntax ([age #'age]) phases, but see §15
“Reflection and
#'(displayln age))) Dynamic
3 Evaluation” for
caveats about eval.
The result is 3 because age is used at phase 0 level. We can try again with the use of age
inside begin-for-syntax:
285
> (eval (with-syntax ([age #'age])
#'(begin-for-syntax
(displayln age))))
9
In this case, the answer is 9, because we are using age at phase level 1 instead of 0 (i.e.,
begin-for-syntax evaluates its expressions at phase level 1). So, you can see that we
started with the same syntax object, #'age, and we were able to use it in two different ways:
at phase level 0 and at phase level 1.
A syntax object has a lexical context from the moment it first exists. A syntax object that
is provided from a module retains its lexical context, and so it references bindings in the
context of its source module, not the context of its use. The following example defines
button at phase level 0 and binds it to 0, while see-button binds the syntax object for
button in module a:
The result of the m macro is the value of see-button, which is #'button with the lexical
context of the a module. Even though there is another button in b, the second button
will not confuse Racket, because the lexical context of #'button (the value bound to see-
button) is a.
Note that see-button is bound at phase level 1 by virtue of defining it with define-for-
syntax. Phase level 1 is needed because m is a macro, so its body executes at one phase
higher than the context of its definition. Since m is defined at phase level 0, its body is at
phase level 1, so any bindings referenced by the body must be at phase level 1.
286
A phase level is a module-relative concept. When importing from another module via re-
quire, Racket lets us shift imported bindings to a phase level that is different from the
original one:
(require "a.rkt") ; import with no phase shift
(require (for-syntax "a.rkt")) ; shift phase by +1
(require (for-template "a.rkt")) ; shift phase by -1
(require (for-meta 5 "a.rkt")) ; shift phase by +5
That is, using for-syntax in require means that all of the bindings from that module will
have their phase levels increased by one. A binding that is defined at phase level 0 and
imported with for-syntax becomes a phase-level 1 binding:
> (module c racket
(define x 0) ; defined at phase level 0
(provide x))
Let’s see what happens if we try to create a binding for the #'button syntax object at phase
level 0:
> (define button 0)
Now both button and see-button are defined at phase 0. The lexical context of #'button
will know that there is a binding for button at phase 0. In fact, it seems like things are
working just fine if we try to eval see-button:
> (eval see-button)
0
> (m)
see-button: undefined;
cannot reference undefined identifier
287
Clearly, see-button is not defined at phase level 1, so we cannot refer to it inside the macro
body. Let’s try to use see-button in another module by putting the button definitions in a
module and importing it at phase level 1. Then, we will get see-button at phase level 1:
Racket says that button is unbound now! When a is imported at phase level 1, we have the
following bindings:
So the macro m can see a binding for see-button at phase level 1 and will return the
#'button syntax object, which refers to button binding at phase level 1. But the use of m
is at phase level 0, and there is no button at phase level 0 in b. That is why see-button
needs to be bound at phase level 1, as in the original a. In the original b, then, we have the
following bindings:
In this scenario, we can use see-button in the macro, since see-button is bound at phase
level 1. When the macro expands, it will refer to a button binding at phase level 0.
288
> (module b racket
(require (for-syntax 'a))
(define-syntax (m stx)
(with-syntax ([x see-button])
#'(begin-for-syntax
(displayln x))))
(m))
0
In this case, module b has both button and see-button bound at phase level 1. The
expansion of the macro is
(begin-for-syntax
(displayln button))
Now, you might try to cheat the phase system by importing a at both phase level 0 and phase
level 1. Then you would have the following bindings
button at phase level 0
see-button at phase level 0
button at phase level 1
see-button at phase level 1
You might expect now that see-button in a macro would work, but it doesn’t:
> (module a racket
(define button 0)
(define see-button #'button)
(provide see-button))
The see-button inside the m macro comes from the (for-syntax 'a) import. For the
macro to work, there must be a button at phase 0 bound, and there is such a binding im-
289
plied by (require 'a). However, (require 'a) and (require (for-syntax 'a))
are different instantiations of the same module. The see-button at phase 1 only refers to
the button at phase level 1, not the button bound at phase 0 from a different instantiation—
even from the same source module.
Mismatches like the one above can show up when a macro tries to match literal bindings—
using syntax-case or syntax-parse.
(provide (all-defined-out))
(define button 0)
(define (make) #'button)
(define-syntax (process stx)
(define-literal-set locals (button))
(syntax-parse stx
[(_ (n (∼literal button))) #'#''ok])))
(begin-for-syntax
(define-syntax (m stx)
(with-syntax ([out (make)])
#'(process (0 out)))))
(define-syntax (p stx)
(m))
(p))
eval:1:0: process: expected the identifier ‘button’
at: button
in: (process (0 button))
In this example, make is being used in y at phase level 2, and it returns the #'button syntax
object—which refers to button bound at phase level 0 inside x and at phase level 2 in y from
(for-meta 2 'x). The process macro is imported at phase level 1 from (for-meta 1
'x), and it knows that button should be bound at phase level 1. When the syntax-parse
is executed inside process, it is looking for button bound at phase level 1 but it sees only
a phase level 2 binding and doesn’t match.
To fix the example, we can provide make at phase level 1 relative to x, and then we import it
290
at phase level 1 in y:
(provide (all-defined-out))
(define button 0)
(begin-for-syntax
(define-syntax (m stx)
(with-syntax ([out (make)])
#'(process (0 out)))))
(define-syntax (p stx)
(m))
(p))
A use of a macro can expand into a use of an identifier that is not exported from the module
that binds the macro. In general, such an identifier must not be extracted from the expanded
expression and used in a different context, because using the identifier in a different context
may break invariants of the macro’s module.
For example, the following module exports a macro go that expands to a use of unchecked-
go:
291
"m.rkt"
#lang racket
(provide go)
(define (unchecked-go n x)
; to avoid disaster, n must be a number
(+ n 17))
If the reference to unchecked-go is extracted from the expansion of (go 'a), then it
might be inserted into a new expression, (unchecked-go #f 'a), leading to disaster. The
datum->syntax procedure can be used similarly to construct references to an unexported
identifier, even when no macro expansion includes a reference to the identifier.
To prevent such abuses of unexported identifiers, the go macro must explicitly protect its
expansion by using syntax-protect:
(define-syntax (go stx)
(syntax-case stx ()
[(_ x)
(syntax-protect #'(unchecked-go 8 x))]))
The syntax-protect function causes any syntax object that is extracted from the result
of go to be tainted. The macro expander rejects tainted identifiers, so attempting to extract
unchecked-go from the expansion of (go 'a) produces an identifier that cannot be used
to construct a new expression (or, at least, not one that the macro expander will accept).
The syntax-rules, syntax-id-rule, and define-syntax-rule forms automatically
protect their expansion results.
More precisely, syntax-protect arms a syntax object with a dye pack. When a syntax
object is armed, then syntax-e taints any syntax object in its result. Similarly, datum-
>syntax taints its result when its first argument is armed. Finally, if any part of a quoted
syntax object is armed, then the corresponding part is tainted in the resulting syntax constant.
Of course, the macro expander itself must be able to disarm a taint on a syntax object, so that
it can further expand an expression or its sub-expressions. When a syntax object is armed
with a dye pack, the dye pack has an associated inspector that can be used to disarm the dye
pack. A (syntax-protect stx ) function call is actually a shorthand for (syntax-arm
stx #f #t), which arms stx using a suitable inspector. The expander uses syntax-
disarm and with its inspector on every expression before trying to expand or compile it.
In much the same way that the macro expander copies properties from a syntax transformer’s
292
input to its output (see §11.7 “Syntax Object Properties”), the expander copies dye packs
from a transformer’s input to its output. Building on the previous example,
"n.rkt"
#lang racket
(require "m.rkt")
(provide go-more)
(define y 'hello)
the expansion of (go-more) introduces a reference to the unexported y in (go y), and the
expansion result is armed so that y cannot be extracted from the expansion. Even if go did not
use syntax-protect for its result (perhaps because it does not need to protect unchecked-
go after all), the dye pack on (go y) is propagated to the final expansion (unchecked-go 8
y). The macro expander uses syntax-rearm to propagate dye packs from a transformer’s
input to its output.
Tainting Modes
In some cases, a macro implementor intends to allow limited destructuring of a macro result
without tainting the result. For example, given the following define-like-y macro,
"q.rkt"
#lang racket
(provide define-like-y)
(define y 'hello)
(let ()
(define-like-y x)
x)
The implementor of the "q.rkt" module most likely intended to allow such uses of
define-like-y. To convert an internal definition into a letrec binding, however, the
293
define form produced by define-like-y must be deconstructed, which would normally
taint both the binding x and the reference to y.
Just like syntax-protect, the expander rearms a transformer result that starts with
define-values, by pushing dye packs into the list elements. As a result, define-like-y
could have been implemented to produce (define id y), which uses define instead of
define-values. In that case, the entire define form is at first armed with a dye pack, but
as the define form is expanded to define-values, the dye pack is moved to the parts.
The macro expander treats syntax-list results starting with define-syntaxes in the same
way that it treats results starting with define-values. Syntax-list results starting with
begin are treated similarly, except that the second element of the syntax list is treated like all
the other elements (i.e., the immediate element is armed, instead of its content). Furthermore,
the macro expander applies this special handling recursively, in case a macro produces a
begin form that contains nested define-values forms.
The default application of dye packs can be overridden by attaching a 'taint-mode prop-
erty (see §11.7 “Syntax Object Properties”) to the result syntax object of a macro trans-
former. If the property value is 'opaque, then the syntax object is armed and not its parts.
If the property value is 'transparent, then the syntax object’s parts are armed. If the
property value is 'transparent-binding, then the syntax object’s parts and to the sub-
parts of the second part (as for define-values and define-syntaxes) are armed. The
'transparent and 'transparent-binding modes triggers recursive property checking
at the parts, so that armings can be pushed arbitrarily deep into a transformer’s result.
Tools that are intended to be privileged (such as a debugging transformer) must disarm dye
packs in expanded programs. Privilege is granted through code inspectors. Each dye pack
records and inspector, and a syntax object can be disarmed using a sufficiently powerful
inspector.
When a module is declared, the declaration captures the current value of the current-
code-inspector parameter. The captured inspector is used when syntax-protect is
applied by a macro transformer that is defined within the module. A tool can disarm the
resulting syntax object by supplying syntax-disarm with an inspector that is the same or
a super-inspector of the module’s inspector. Untrusted code is ultimately run after setting
current-code-inspector to a less powerful inspector (after trusted code, such as debug-
ging tools, have been loaded).
294
With this arrangement, macro-generating macros require some care, since the generating
macro may embed syntax objects in the generated macro that need to have the generat-
ing module’s protection level, rather than the protection level of the module that contains
the generated macro. To avoid this problem, use the module’s declaration-time inspec-
tor, which is accessible as (variable-reference->module-declaration-inspector
(#%variable-reference)), and use it to define a variant of syntax-protect.
#lang racket
(provide def-go)
(define (unchecked-go n x)
(+ n 17))
When def-go is used inside another module to defined go, and when the go-defining module
is at a different protection level than the def-go-defining module, the generated macro’s use
of protect-syntax is not right. The use of unchecked-go should be protected at the level
of the def-go-defining module, not the go-defining module.
#lang racket
(provide def-go)
(define (unchecked-go n x)
(+ n 17))
(define-for-syntax go-syntax-protect
(let ([insp (variable-reference->module-declaration-inspector
(#%variable-reference))])
(lambda (stx) (syntax-arm stx insp))))
295
#'(define-syntax (go stx)
(syntax-case stx ()
[(_ x)
(go-syntax-protect #'(unchecked-go 8 x))])))]))
Protected Exports
Sometimes, a module needs to export bindings to some modules—other modules that are at
the same trust level as the exporting module—but prevent access from untrusted modules.
Such exports should use the protect-out form in provide. For example, ffi/unsafe
exports all of its unsafe bindings as protected in this sense.
Code inspectors, again, provide the mechanism for determining which modules are trusted
and which are untrusted. When a module is declared, the value of current-code-
inspector is associated to the module declaration. When a module is instantiated (i.e.,
when the body of the declaration is actually executed), a sub-inspector is created to guard
the module’s exports. Access to the module’s protected exports requires a code inspector
higher in the inspector hierarchy than the module’s instantiation inspector; note that a mod-
ule’s declaration inspector is always higher than its instantiation inspector, so modules are
declared with the same code inspector can access each other’s exports.
Syntax-object constants within a module, such as literal identifiers in a template, retain the
inspector of their source module. In this way, a macro from a trusted module can be used
within an untrusted module, and protected identifiers in the macro expansion still work, even
through they ultimately appear in an untrusted module. Naturally, such identifiers should be
armed, so that they cannot be extracted from the macro expansion and abused by untrusted
code.
Compiled code from a ".zo" file is inherently untrustworthy, unfortunately, since it can be
synthesized by means other than compile. When compiled code is written to a ".zo" file,
syntax-object constants within the compiled code lose their inspectors. All syntax-object
constants within compiled code acquire the enclosing module’s declaration-time inspector
when the code is loaded.
296
17 Creating Languages
The macro facilities defined in the preceding chapter let a programmer define syntactic ex-
tensions to a language, but a macro is limited in two ways:
• a macro cannot restrict the syntax available in its context or change the meaning of
surrounding forms; and
• a macro can extend the syntax of a language only within the parameters of the lan-
guage’s lexical conventions, such as using parentheses to group the macro name with
its subforms and using the core syntax of identifiers, keywords, and literals.
The distinction
between the reader
That is, a macro can only extend a language, and it can do so only at the expander layer. and expander layer
Racket offers additional facilities for defining a starting point of the expander layer, for ex- is introduced in
§2.4.3 “Lists and
tending the reader layer, for defining the starting point of the reader layer, and for packaging Racket Syntax”.
a reader and expander starting point into a conveniently named language.
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 bind-
ings from racket to produce a module language that is a variant of racket: §6.2.1 “The
module Form”
> (module raquet racket introduces the
longhand module
(provide (except-out (all-from-out racket) lambda) form.
(rename-out [lambda function])))
297
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:
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:
The other implicit forms provided by racket/base are #%app for function calls, #%datum
for literals, and #%top for identifiers that have no binding:
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
298
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:
299
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 descrip-
tions of HTML pages where a description is exported from the module as page, an al-
ternate #%module-begin can help eliminate provide and quasiquoting boilerplate, as in
"html.rkt":
"html.rkt"
#lang racket
(require racket/date)
(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 hav-
ing to explicitly define or export page and starting in quasiquoted mode instead of expres-
sion mode:
> page
'(html (title "Queen of Diamonds") (p "Updated: " "2012-11-06"))
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
300
s-exp language, however, acts as a kind of meta-language for using a module language with
the #lang shorthand:
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.
Later in this guide, §17.3 “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.
The reader layer of the Racket language can be extended through the #reader form. A
reader extension is implemented as a module that is named after #reader. The module
exports functions that parse raw characters into a form to be consumed by the expander
layer.
where hmodule-pathi names a module that provides read and read-syntax functions. The
hreader-specifici part is a sequence of characters that is parsed as determined by the read
and read-syntax functions from hmodule-pathi.
301
"five.rkt"
#lang racket/base
#lang racket/base
'(1 #reader"five.rkt"234567 8)
is equivalent to
#lang racket/base
'(1 ("23456") 7 8)
because the read and read-syntax functions of "five.rkt" both read five characters
from the input stream and put them into a string and then a list. The reader functions from
"five.rkt" are not obliged to follow Racket lexical conventions and treat the continuous
sequence 234567 as a single number. Since only the 23456 part is consumed by read or
read-syntax, the 7 remains to be parsed in the usual Racket way. Similarly, the reader
functions from "five.rkt" are not obliged to ignore whitespace, and
#lang racket/base
is equivalent to
#lang racket/base
> '#reader"five.rkt"abcde
'("abcde")
302
17.2.1 Source Locations
The difference between read and read-syntax is that read is meant to be used for data
while read-syntax is meant to be used to parse programs. More precisely, the read func-
tion will be used when the enclosing stream is being parsed by the Racket read, and read-
syntax is used when the enclosing stream is being parsed by the Racket read-syntax
function. Nothing requires read and read-syntax to parse input in the same way, but
making them different would confuse programmers and tools.
The read-syntax function can return the same kind of value as read, but it should normally
return a syntax object that connects the parsed expression with source locations. Unlike
the "five.rkt" example, the read-syntax function is typically implemented directly to
produce syntax objects, and then read can use read-syntax and strip away syntax object
wrappers to produce a raw result.
The following "arith.rkt" module implements a reader to parse simple infix arithmetic
expressions into Racket forms. For example, 1*2+3 parses into the Racket form (+ (* 1
2) 3). The supported operators are +, -, *, and /, while operands can be unsigned integers
or single-letter variables. The implementation uses port-next-location to obtain the
current source location, and it uses datum->syntax to turn raw values into syntax objects.
"arith.rkt"
#lang racket
(require syntax/readerr)
303
(define (to-syntax v delta span-str)
(datum->syntax #f v (make-srcloc delta span-str)))
(define (make-srcloc delta span-str)
(and line
(vector src line (+ col delta) (+ pos delta)
(string-length span-str))))
(unless expr-match
(raise-read-error "bad arithmetic syntax"
src line col pos
(and pos (- (file-position in) pos))))
(parse-expr (bytes->string/utf-8 (car expr-match)) 0))
If the "arith.rkt" reader is used in an expression position, then its parse result will be
treated as a Racket expression. If it is used in a quoted form, however, then it just produces
a number or a list:
> #reader"arith.rkt" 1*2+3
5
> '#reader"arith.rkt" 1*2+3
'(+ (* 1 2) 3)
The "arith.rkt" reader could also be used in positions that make no sense. Since the
read-syntax implementation tracks source locations, syntax errors can at least refer to
parts of the input in terms of their original locations (at the beginning of the error message):
> (let #reader"arith.rkt" 1*2+3 8)
repl:1:27: let: bad syntax (not an identifier and expression
for a binding)
at: +
in: (let (+ (* 1 2) 3) 8)
304
17.2.2 Readtables
A reader extension’s ability to parse input characters in an arbitrary way can be powerful,
but many cases of lexical extension call for a less general but more composable approach.
In much the same way that the expander level of Racket syntax can be extended through
macros, the reader level of Racket syntax can be composably extended through a readtable.
The Racket reader is a recursive-descent parser, and the readtable maps characters to parsing
handlers. For example, the default readtable maps ( to a handler that recursively parses
subforms until it finds a ). The current-readtable parameter determines the readtable
that is used by read or read-syntax. Rather than parsing raw characters directly, a reader
extension can install an extended readtable and then chain to read or read-syntax. See §4.13
“Dynamic Binding:
The make-readtable function constructs a new readtable as an extension of an existing parameterize”
for an introduction
one. It accepts a sequence of specifications in terms of a character, a type of mapping for to parameters.
the character, and (for certain types of mappings) a parsing procedure. For example, to
extend the readtable so that $ can be used to start and end infix expressions, implement a
read-dollar function and use:
(make-readtable (current-readtable)
#\$ 'terminating-macro read-dollar)
The protocol for read-dollar requires the function to accept different numbers of argu-
ments depending on whether it is being used in read or read-syntax mode. In read
mode, the parser function is given two arguments: the character that triggered the parser
function and the input port that is being read. In read-syntax mode, the function must
accept four additional arguments that provide the source location of the character.
The following "dollar.rkt" module defines a read-dollar function in terms of the read
and read-syntax functions provided by "arith.rkt", and it puts read-dollar together
with new read and read-syntax functions that install the readtable and chain to Racket’s
read or read-syntax:
"dollar.rkt"
#lang racket
(require syntax/readerr
(prefix-in arith: "arith.rkt"))
305
(parameterize ([current-readtable (make-$-readtable)])
(read-syntax src in)))
(define (make-$-readtable)
(make-readtable (current-readtable)
#\$ 'terminating-macro read-dollar))
(define read-dollar
(case-lambda
[(ch in)
(check-$-after (arith:read in) in (object-name in))]
[(ch in src line col pos)
(check-$-after (arith:read-syntax src in) in src)]))
With this reader extension, a single #reader can be used at the beginning of an expression
to enable multiple uses of $ that switch to infix arithmetic:
#lang language
the language determines the way that the rest of the module is parsed at the reader level.
The reader-level parse must produce a module form as a syntax object. As always, the
306
second sub-form after module specifies the module language that controls the meaning of
the module’s body forms. Thus, a language specified after #lang controls both the reader-
level and expander-level parsing of a module.
The syntax of a language intentionally overlaps with the syntax of a module path as used in
require or as a module language, so that names like racket, racket/base, slideshow,
or scribble/manual can be used both as #lang languages and as module paths.
At the same time, the syntax of language is far more restricted than a module path, because
only a-z, A-Z, 0-9, / (not at the start or end), _, -, and + are allowed in a language name.
These restrictions keep the syntax of #lang as simple as possible. Keeping the syntax of
#lang simple, in turn, is important because the syntax is inherently inflexible and non-
extensible; the #lang protocol allows a language to refine and define syntax in a practically
unconstrained way, but the #lang protocol itself must remain fixed so that various different
tools can “boot” into the extended world.
Fortunately, the #lang protocol provides a natural way to refer to languages in ways other
than the rigid language syntax: by defining a language that implements its own nested
protocol. We have already seen one example (in §17.1.2 “Using #lang s-exp”): the s-exp
language allows a programmer to specify a module language using the general module
path syntax. Meanwhile, s-exp takes care of the reader-level responsibilities of a #lang
language.
Unlike racket, s-exp cannot be used as a module path with require. Although the syntax
of language for #lang overlaps with the syntax of module paths, a language is not used
directly as a module path. Instead, a language is suffixed with /lang/reader to obtain a
module path, and the resulting module supplies read and read-syntax functions using a
protocol that is similar to the one for #reader. §17.2 “Reader
Extensions”
A consequence of the way that a #lang language is turned into a module path is that introduces
#reader.
the language must be installed in a collection, similar to the way that "racket" or
"slideshow" are collections that are distributed with Racket. Again, however, there’s an
escape from this restriction: the reader language lets you specify a reader-level implemen-
tation of a language using a general module path.
The reader language for #lang is similar to s-exp, in that it acts as a kind of meta-
language. Whereas s-exp lets a programmer specify a module language at the expander
layer of parsing, reader lets a programmer specify a language at the reader level.
A #lang reader must be followed by a module path, and the specified module must pro-
307
vide two functions: read and read-syntax. The protocol is the same as for a #reader
implementation, but for #lang, the read and read-syntax functions must produce a mod-
ule form that is based on the rest of the input file for the module.
The following "literal.rkt" module implements a language that treats its entire body as
literal text and exports the text as a data string:
"literal.rkt"
#lang racket
(require syntax/strip-context)
"tuvalu.rkt"
#lang reader "literal.rkt"
Technology!
System!
Perfect!
> data
"\nTechnology!\nSystem!\nPerfect!\n"
308
17.3.3 Using #lang s-exp syntax/module-reader
Parsing a module body is usually not as trivial as in "literal.rkt". A more typical module
parser must iterate to parse multiple forms for a module body. A language is also more likely
to extend Racket syntax—perhaps through a readtable—instead of replacing Racket syntax
completely.
and
"raquet.rkt"
#lang s-exp syntax/module-reader
"raquet-mlang.rkt"
then
#lang reader "raquet.rkt"
(define identity (function (x) x))
(provide identity)
309
The require form appears at the end of the module, because all of the keyword-tagged
optional specifications for syntax/module-reader must appear before any helper imports
or definitions.
"store.rkt"
#lang reader "dollar-racket.rkt"
(provide cost)
So far, we have used the reader meta-language to access languages like "literal.rkt"
and "dollar-racket.rkt". If you want to use something like #lang literal directly,
then you must move "literal.rkt" into a Racket collection named "literal".
There are two ways to create the "literal" collection (see also §6.1.3 “Adding Collec-
tions”):
• You can create a directory either in the main Racket installation or in a user-
specific directory. Use find-collects-dir or find-user-collects-dir from
setup/dirs to find the directory:
> (find-user-collects-dir)
#<path:/home/racketeer/.racket/5.3.1/collects>
310
• Alternatively, move "literal.rkt" to "literal/lang/reader.rkt" for any di-
rectory name "literal". Then, in the directory that contains "literal", use the
command line
raco link literal
to register the "literal" directory as the "literal" collection.
After moving the file, you can use literal directly after #lang:
#lang literal
Technology!
System!
Perfect!
See raco: Racket
Command-Line
You can also package a collection for others to install by using the raco pack command- Tools for more
information on
line tool: using raco.
Then, others can install the "literal" collection using raco setup:
The Racket distribution includes a Scribble language for writing prose documents, where
Scribble extends the normal Racket to better support text. Here is an example Scribble
document:
#lang scribble/base
@title[(get-name)]
If you put that program in DrRacket’s definitions area and click Run, then nothing much ap-
pears to happen. The scribble/base language just binds and exports doc as a description
of a document, similar to the way that "literal.rkt" exports a string as data.
311
Simply opening a module with the language scribble/base in DrRacket, however, causes
a Scribble HTML button to appear. Furthermore, DrRacket knows how to colorize Scribble
syntax by coloring green those parts of the document that correspond to literal text. The
language name scribble/base is not hard-wired into DrRacket. Instead, the implemen-
tation of the scribble/base language provides button and syntax-coloring information in
response to a query from DrRacket.
For security reasons, only languages that have been specifically installed by a user
can respond to language-information queries. If you have installed the literal
language as described in §17.3.4 “Installing a Language”, then you can adjust
"literal/lang/reader.rkt" so that DrRacket treats the content of a module in the lit-
eral language as plain text instead of (erroneously) as Racket syntax:
"literal/lang/reader.rkt"
#lang racket
(require syntax/strip-context)
This revised literal implementation provides a get-info function. The get-info func-
tion will be applied to the source input stream and location information, in case query results
should depend on the content of the module after the language name (which is not the case
for literal). The result of get-info is a function of two arguments. The first argument is
always a symbol, indicating the kind of information that a tool requests from the language;
the second argument is the default result to be returned if the language does not recognize
312
the query or has no information for it.
After DrRacket obtains the result of get-info for a language, it calls the function with
a 'color-lexer query; the result should be a function that implements syntax-coloring
parsing on an input stream. For literal, the syntax-color/default-lexer module
provides a default-lexer syntax-coloring parser that is suitable for plain text, so literal
loads and returns that parser in response to a 'color-lexer query.
The set of symbols that a programming tool uses for queries is entirely between the tool and
the languages that choose to cooperate with it. For example, in addition to 'color-lexer,
DrRacket uses a 'drracket:toolbar-buttons query to determine which buttons should
be available in the toolbar to operate on modules using the language.
"death-list-5.rkt"
#lang racket
(list "O-Ren Ishii"
"Vernita Green"
"Budd"
"Elle Driver"
"Bill")
If you require "death-list-5.rkt" directly, then it prints the list in the usual Racket
result format:
"kiddo.rkt"
#lang scheme
(require "death-list-5.rkt")
313
then, if you run "kiddo.rkt" file in DrRacket or if you run it directly with racket,
"kiddo.rkt" causes "death-list-5.rkt" to print its list in traditional Scheme format,
without the leading quote:
The "kiddo.rkt" example illustrates how the format for printing a result value can depend
on the main module of a program instead of the language that is used to implement it.
314
Multiple modules are needed to implement the printing change, because the different mod-
ules must run at different times. For example, the code needed to parse a literal module
is not needed after the module has been compiled, while the run-time configuration code
is needed only when the module is run as the main module of a program. Similarly, when
creating a stand-alone executable with raco exe, the main module (in compiled form) must
be queried for its run-time configuration, but the module and its configuration action should
not run until the executable is started. By using different modules for these different tasks,
we avoid loading code at times when it is not needed.
The three new files are connected to the literal language by changes to
"literal/lang/reader.rkt":
• The module form generated by the read-syntax function must import the lit-
eral/show module and call its show function.
• The module form must be annotated with a 'language-info syntax property, whose
value points to a get-language-info function exported by a literal/language-
info module. The get-language-info function will be responsible for reporting
the literal/runtime-config as the run-time configuration action of the language.
The 'language-info syntax property value is a vector that contains a module (in
this case literal/language-info), a symbol for one of the module’s exports (get-
language-info in this case), and an data value (which is not needed in this case). The
data component allows information to be propagated from the source to the module’s
language information.
"literal/lang/reader.rkt"
#lang racket
(require syntax/strip-context)
315
(provide data)
(define data 'str)
(show data)))
'module-language
'#(literal/language-info get-language-info #f))))
When a module form with a 'module-language property is compiled, the property value
is preserved with the compiled module, and it is accessible via reflective functions like
module->language-info. When racket or DrRacket runs a module, it uses module-
>language-info to obtain a vector that contains a module name, export name, and data
value. The result of the function applied to the data should be another function that answers
queries, much like the get-info function in a language reader.
"literal/language-info.rkt"
#lang racket
(provide get-language-info)
"literal/runtime-config.rkt"
#lang racket
(require "show.rkt")
(provide configure)
316
(define (configure data)
(show-enabled #t))
Finally, the "literal/show.rkt" module must provide the show-enabled parameter and
show function:
"literal/show.rkt"
#lang racket
(define (show v)
(when (show-enabled)
(display v)))
With all of the pieces for literal in place, try running the following variant of
"tuvalu.rkt" directly and through a require from another module:
"tuvalu.rkt"
#lang literal
Technology!
System!
Perfect!
317
18 Performance
Alan Perlis famously quipped “Lisp programmers know the value of everything and the
cost of nothing.” A Racket programmer knows, for example, that a lambda anywhere in a
program produces a value that is closed over its lexical environment—but how much does
allocating that value cost? While most programmers have a reasonable grasp of the cost
of various operations and data structures at the machine level, the gap between the Racket
language model and the underlying computing machinery can be quite large.
In this chapter, we narrow the gap by explaining details of the Racket compiler and run-time
system and how they affect the run-time and memory performance of Racket code.
Even so, DrRacket and programs developed within DrRacket use the same Racket virtual
machine, so garbage collection times (see §18.9 “Memory Management”) may be longer
in DrRacket than when a program is run by itself, and DrRacket threads may impede exe-
cution of program threads. For the most reliable timing results for a program, run in plain
racket instead of in the DrRacket development environment. Non-interactive mode should
be used instead of the REPL to benefit from the module system. See §18.3 “Modules and
Performance” for details.
The bytecode compiler applies all standard optimizations, such as constant propagation,
constant folding, inlining, and dead-code elimination. For example, in an environment where
+ has its usual binding, the expression (let ([x 1] [y (lambda () 4)]) (+ 1 (y)))
318
is compiled the same as the constant 5.
On some platforms, bytecode is further compiled to native code via a just-in-time or JIT com-
piler. The JIT compiler substantially speeds programs that execute tight loops, arithmetic on
small integers, and arithmetic on inexact real numbers. Currently, JIT compilation is sup-
ported for x86, x86_64 (a.k.a. AMD64), and 32-bit PowerPC processors. The JIT compiler
can be disabled via the eval-jit-enabled parameter or the --no-jit/-j command-line
flag for racket.
The JIT compiler works incrementally as functions are applied, but the JIT compiler makes
only limited use of run-time information when compiling procedures, since the code for a
given module body or lambda abstraction is compiled only once. The JIT’s granularity
of compilation is a single procedure body, not counting the bodies of any lexically nested
procedures. The overhead for JIT compilation is normally so small that it is difficult to
detect.
The module system aids optimization by helping to ensure that identifiers have the usual
bindings. That is, the + provided by racket/base can be recognized by the compiler and
inlined, which is especially important for JIT-compiled code. In contrast, in a traditional in-
teractive Scheme system, the top-level + binding might be redefined, so the compiler cannot
assume a fixed + binding (unless special flags or declarations are used to compensate for the
lack of a module system).
Even in the top-level environment, importing with require enables some inlining optimiza-
tions. Although a + definition at the top level might shadow an imported +, the shadowing
definition applies only to expressions evaluated later.
The compiler may inline functions or propagate constants across module boundaries. To
avoid generating too much code in the case of function inlining, the compiler is conservative
when choosing candidates for cross-module inlining; see §18.4 “Function-Call Optimiza-
tions” for information on providing inlining hints to the compiler.
The later section §18.6 “letrec Performance” provides some additional caveats concerning
inlining of module bindings.
319
18.4 Function-Call Optimizations
When the compiler detects a function call to an immediately visible function, it generates
more efficient code than for a generic call, especially for tail calls. For example, given the
program
the compiler can detect the odd–even loop and produce code that runs much faster via loop
unrolling and related optimizations.
Within a module form, defined variables are lexically scoped like letrec bindings, and
definitions within a module therefore permit call optimizations, so
For direct calls to functions with keyword arguments, the compiler can typically check key-
word arguments statically and generate a direct call to a non-keyword variant of the function,
which reduces the run-time overhead of keyword checking. This optimization applies only
for keyword-accepting procedures that are bound with define.
For immediate calls to functions that are small enough, the compiler may inline the function
call by replacing the call with the body of the function. In addition to the size of the target
function’s body, the compiler’s heuristics take into account the amount of inlining already
performed at the call site and whether the called function itself calls functions other than
simple primitive operations. When a module is compiled, some functions defined at the
module level are determined to be candidates for inlining into other modules; normally, only
trivial functions are considered candidates for cross-module inlining, but a programmer can
wrap a function definition with begin-encourage-inline to encourage inlining of the
function.
Primitive operations like pair?, car, and cdr are inlined at the machine-code level by
the JIT compiler. See also the later section §18.7 “Fixnum and Flonum Optimizations” for
information about inlined arithmetic operations.
320
18.5 Mutation and Performance
Using set! to mutate a variable can lead to bad performance. For example, the microbench-
mark
#lang racket/base
(define (subtract-one x)
(set! x (sub1 x))
x)
(time
(let loop ([n 4000000])
(if (zero? n)
'done
(loop (subtract-one n)))))
(define (subtract-one x)
(sub1 x))
(time
(let loop ([n 4000000])
(if (zero? n)
'done
(loop (subtract-one n)))))
In the first variant, a new location is allocated for x on every iteration, leading to poor perfor-
mance. A more clever compiler could unravel the use of set! in the first example, but since
mutation is discouraged (see §4.9.1 “Guidelines for Using Assignment”), the compiler’s
effort is spent elsewhere.
More significantly, mutation can obscure bindings where inlining and constant-propagation
might otherwise apply. For example, in
(let ([minus1 #f])
(set! minus1 sub1)
(let loop ([n 4000000])
(if (zero? n)
'done
(loop (minus1 n)))))
the set! obscures the fact that minus1 is just another name for the built-in sub1.
321
18.6 letrec Performance
When letrec is used to bind only procedures and literals, then the compiler can treat the
bindings in an optimal manner, compiling uses of the bindings efficiently. When other kinds
of bindings are mixed with procedures, the compiler may be less able to determine the con-
trol flow.
For example,
(letrec ([loop (lambda (x)
(if (zero? x)
'done
(loop (next x))))]
[junk (display loop)]
[next (lambda (x) (sub1 x))])
(loop 40000000))
In the first case, the compiler likely does not know that display does not call loop. If it
did, then loop might refer to next before the binding is available.
This caveat about letrec also applies to definitions of functions and constants as internal
definitions or in modules. A definition sequence in a module body is analogous to a sequence
of letrec bindings, and non-constant expressions in a module body can interfere with the
optimization of references to later bindings.
A fixnum is a small exact integer. In this case, “small” depends on the platform. For a 32-bit
machine, numbers that can be expressed in 30 bits plus a sign bit are represented as fixnums.
On a 64-bit machine, 62 bits plus a sign bit are available.
A flonum is used to represent any inexact real number. They correspond to 64-bit IEEE
floating-point numbers on all platforms.
Inlined fixnum and flonum arithmetic operations are among the most important advantages
of the JIT compiler. For example, when + is applied to two arguments, the generated machine
322
code tests whether the two arguments are fixnums, and if so, it uses the machine’s instruction
to add the numbers (and check for overflow). If the two numbers are not fixnums, then it
checks whether both are flonums; in that case, the machine’s floating-point operations are
used directly. For functions that take any number of arguments, such as +, inlining works
for two or more arguments (except for -, whose one-argument case is also inlined) when the
arguments are either all fixnums or all flonums.
Flonums are typically boxed, which means that memory is allocated to hold every result of
a flonum computation. Fortunately, the generational garbage collector (described later in
§18.9 “Memory Management”) makes allocation for short-lived results reasonably cheap.
Fixnums, in contrast are never boxed, so they are typically cheap to use. See §18.10
“Parallelism with
The racket/flonum library provides flonum-specific operations, and combinations of Futures” for an
example use of
flonum operations allow the JIT compiler to generate code that avoids boxing and unboxing flonum-specific
intermediate results. Besides results within immediate combinations, flonum-specific results operations.
that are bound with let and consumed by a later flonum-specific operation are unboxed
within temporary storage. Finally, the compiler can detect some flonum-valued loop accu-
mulators and avoid boxing of the accumulator. The bytecode decompiler (see §9 “raco de-
compile: Decompiling Bytecode”) annotates combinations where the JIT can avoid boxes
with #%flonum, #%as-flonum, and #%from-flonum. Unboxing of local
bindings and
The racket/unsafe/ops library provides unchecked fixnum- and flonum-specific oper- accumualtors is not
supported by the
ations. Unchecked flonum-specific operations allow unboxing, and sometimes they allow JIT for PowerPC.
the compiler to reorder expressions to improve performance. See also §18.8 “Unchecked,
Unsafe Operations”, especially the warnings about unsafety.
The racket/unsafe/ops library provides functions that are like other functions in
racket/base, but they assume (instead of checking) that provided arguments are of the
right type. For example, unsafe-vector-ref accesses an element from a vector without
checking that its first argument is actually a vector and without checking that the given index
is in bounds. For tight loops that use these functions, avoiding checks can sometimes speed
the computation, though the benefits vary for different unchecked functions and different
contexts.
Beware that, as “unsafe” in the library and function names suggest, misusing the exports of
racket/unsafe/ops can lead to crashes or memory corruption.
The Racket implementation is available in two variants: 3m and CGC. The 3m variant uses
a modern, generational garbage collector that makes allocation relatively cheap for short-
323
lived objects. The CGC variant uses a conservative garbage collector which facilitates in-
teraction with C code at the expense of both precision and speed for Racket memory man-
agement. The 3m variant is the standard one.
no closure is ever allocated for prev-thunk, because its only application is visible, and so
it is inlined. Similarly, in
then the expansion of the let form to implement m-loop involves a closure over n, but the
compiler automatically converts the closure to pass itself n as an argument instead.
The racket/future library provides support for performance improvement through paral-
lelism with the future and touch functions. The level of parallelism available from those
constructs, however, is limited by several factors, and the current implementation is best
suited to numerical tasks. Other functions,
such as thread,
support the creation
324 of reliably
concurrent tasks.
However, threads
never run truly in
parallel, even if the
hardware and
operating system
support parallelism.
As a starting example, the any-double? function below takes a list of numbers and deter-
mines whether any number in the list has a double that is also in the list:
(define (any-double? l)
(for/or ([i (in-list l)])
(for/or ([i2 (in-list l)])
(= i2 (* 2 i)))))
This function runs in quadratic time, so it can take a long time (on the order of a second) on
large lists like l1 and l2:
The future f runs (any-double? l2) in parallel to (any-double? l1), and the result for
(any-double? l2) becomes available about the same time that it is demanded by (touch
f).
Futures run in parallel as long as they can do so safely, but the notion of “future safe”
is inherently tied to the implementation. The distinction between “future safe” and “future
unsafe” operations may be far from apparent at the level of a Racket program. The remainder
of this section works through an example to illustrate this distinction and to show how to use
the future visualizer can help shed light on it.
325
[ziq (* zi zi)])
(cond
[(> (+ zrq ziq) 4) i]
[else (loop (add1 i)
(+ (- zrq ziq) cr)
(+ (* 2 zr zi) ci))]))))))
Unfortunately, attempting to run the two computations in parallel with future does not
improve performance:
(let ([f (future (lambda () (mandelbrot 10000000 62 501 1000)))])
(list (mandelbrot 10000000 62 500 1000)
(touch f)))
This opens a window showing a graphical view of a trace of the computation. The upper-left
portion of the window contains an execution timeline:
Thread 2
326
Each horizontal row represents an OS-level thread, and the colored dots represent important
events in the execution of the program (they are color-coded to distinguish one event type
from another). The upper-left blue dot in the timeline represents the future’s creation. The
future executes for a brief period (represented by a green bar in the second line) on thread 1,
and then pauses to allow the runtime thread to perform a future-unsafe operation.
In the Racket implementation, future-unsafe operations fall into one of two categories. A
blocking operation halts the evaluation of the future, and will not allow it to continue until it
is touched. After the operation completes within touch, the remainder of the future’s work
will be evaluated sequentially by the runtime thread. A synchronized operation also halts the
future, but the runtime thread may perform the operation at any time and, once completed,
the future may continue running in parallel. Memory allocation and JIT compilation are two
common examples of synchronized operations.
In the timeline, we see an orange dot just to the right of the green bar on thread 1 – this dot
represents a synchronized operation (memory allocation). The first orange dot on thread 0
shows that the runtime thread performed the allocation shortly after the future paused. A
short time later, the future halts on a blocking operation (the first red dot) and must wait until
the touch for it to be evaluated (slightly after the 1049ms mark).
When you move your mouse over an event, the visualizer shows you detailed information
about the event and draws arrows connecting all of the events in the corresponding future.
This image shows those connections for our future.
Thread 2
The dotted orange line connects the first event in the future to the future that created it, and
the purple lines connect adjacent events within the future.
The reason that we see no parallelism is that the < and * operations in the lower portion of
the loop in mandelbrot involve a mixture of floating-point and fixed (integer) values. Such
mixtures typically trigger a slow path in execution, and the general slow path will usually be
blocking.
327
Changing constants to be floating-points numbers in mandelbrot addresses that first prob-
lem:
With that change, mandelbrot computations can run in parallel. Nevertheless, we still see
a special type of slow-path operation limiting our parallelism (orange dots):
The problem is that most every arithmetic operation in this example produces an inexact
number whose storage must be allocated. While some allocation can safely be performed
exclusively without the aid of the runtime thread, especially frequent allocation requires
synchronized operations which defeat any performance improvement.
328
[else (loop (add1 i)
(fl+ (fl- zrq ziq) cr)
(fl+ (fl* 2.0 (fl* zr zi)) ci))]))))))
This conversion can speed mandelbrot by a factor of 8, even in sequential mode, but avoid-
ing allocation also allows mandelbrot to run usefully faster in parallel. Executing this
program yields the following in the visualizer:
Notice that only one green bar is shown here because one of the mandelbrot computations is
not being evaluated by a future (on the runtime thread).
As a general guideline, any operation that is inlined by the JIT compiler runs safely in par-
allel, while other operations that are not inlined (including all operations if the JIT compiler
is disabled) are considered unsafe. The raco decompile tool annotates operations that
can be inlined by the compiler (see §9 “raco decompile: Decompiling Bytecode”), so the
decompiler can be used to help predict parallel performance.
The racket/place library provides support for performance improvement through paral-
lelism with the place form. The place form creates a place, which is effectively a new
Racket instance that can run in parallel to other places, including the initial place. The full
power of the Racket language is available at each place, but places can communicate only
through message passing—using the place-channel-put and place-channel-get func-
tions on a limited set of values—which helps ensure the safety and independence of parallel
computations.
As a starting example, the racket program below uses a place to determine whether any
number in the list has a double that is also in the list:
#lang racket
(provide main)
(define (any-double? l)
(for/or ([i (in-list l)])
(for/or ([i2 (in-list l)])
329
(= i2 (* 2 i)))))
(define (main)
(define p
(place ch
(define l (place-channel-get ch))
(define l-double? (any-double? l))
(place-channel-put ch l-double?)))
(place-channel-get p))
The identifier ch after place is bound to a place channel. The remaining body expressions
within the place form are evaluated in a new place, and the body expressions use ch to
communicate with the place that spawned the new place.
In the body of the place form above, the new place receives a list of numbers over ch and
binds the list to l. It then calls any-double? on the list and binds the result to l-double?.
The final body expression sends the l-double? result back to the original place over ch.
In DrRacket, after saving and running the above program, evaluate (main) in the interac-
tions window to create the new place. Alternatively, save the program as "double.rkt" When using places
and run from a command line with inside DrRacket,
the module
containg place code
racket -tm double.rkt must be saved to a
file before it will
where the -t flag tells racket to load the double.rkt module, the -m flag calls the exported execute.
main function, and -tm combines the two flags.
The place form has two subtle features. First, it lifts the place body to an anonymous,
module-level function. This lifting means that any binding referenced by the place body
must be available in the module’s top level. Second, the place form dynamic-requires
the enclosing module in a newly created place. As part of the dynamic-require, the current
module body is evaluated in the new place. The consequence of this second feature is that
place should not appear immediately in a module or in a function that is called in a module’s
top level; otherwise, invoking the module will invoke the same module in a new place, and
so on, triggering a cascade of place creations that will soon exhaust memory.
#lang racket
(provide main)
; Don't do this!
(define p (place ch (place-channel-get ch)))
(define (indirect-place-invocation)
330
(define p2 (place ch (place-channel-get ch))))
The example bellow demonstrates how to launch a remote racket node instance, launch
remote places on the new remote node instance, and start an event loop that monitors the
remote node instance.
The code for the tuple-server place exists in the file "tuple.rkt". The "tuple.rkt"
file contains the use of define-named-remote-server form, which defines a RPC server
suitiable for invocation by supervise-named-dynamic-place-at.
The define-rpc form is expanded into two parts. The first part is the client stubs that
call the rpc functions. The client function name is formed by concatenating the define-
named-remote-server identifier, tuple-server, with the RPC function name set to
form tuple-server-set. The RPC client functions take a destination argument which
is a remote-connection% descriptor and then the RPC function arguments. The RPC
client function sends the RPC function name, set, and the RPC arguments to the destination
by calling an internal function named-place-channel-put. The RPC client then calls
named-place-channel-get to wait for the RPC response.
The second expansion part of define-rpc is the server implementation of the RPC call.
331
#lang racket/base
(require racket/place/distributed
racket/class
racket/place
racket/runtime-path
"bank.rkt"
"tuple.rkt")
(define-runtime-path bank-path "bank.rkt")
(define-runtime-path tuple-path "tuple.rkt")
(provide main)
(define (main)
(define remote-node (spawn-remote-racket-node
"localhost"
#:listen-port 6344))
(define tuple-place (supervise-place-at
remote-node
#:named 'tuple-server
tuple-path
'make-tuple-server))
(define bank-place (supervise-place-at
remote-node bank-path
'make-bank))
(message-router
remote-node
(after-seconds 4
(displayln (bank-new-account bank-place 'user0))
(displayln (bank-add bank-place 'user0 10))
(displayln (bank-removeM bank-place 'user0 5)))
(after-seconds 2
(define c (connect-to-named-place remote-node
'tuple-server))
(define d (connect-to-named-place remote-node
'tuple-server))
(tuple-server-hello c)
(tuple-server-hello d)
(displayln (tuple-server-set c "user0" 100))
(displayln (tuple-server-set d "user2" 200))
(displayln (tuple-server-get c "user0"))
(displayln (tuple-server-get d "user2"))
(displayln (tuple-server-get d "user0"))
(displayln (tuple-server-get c "user2"))
)
(after-seconds 8
(node-send-exit remote-node))
(after-seconds 10 332
(exit 0))))
Figure 1: examples/named/master.rkt
#lang racket/base
(require racket/match
racket/place/define-remote-server)
(define-named-remote-server tuple-server
(define-state h (make-hash))
(define-rpc (set k v)
(hash-set! h k v)
v)
(define-rpc (get k)
(hash-ref h k #f))
(define-cast (hello)
(printf "Hello from define-cast\n")
(flush-output)))
Figure 2: examples/named/tuple.rkt
The define-cast form is similar to the define-rpc form except there is no reply message
from the server to client
333
(module tuple racket/base
(require racket/place
racket/match)
(define/provide
(tuple-server-set dest k v)
(named-place-channel-put dest (list 'set k v))
(named-place-channel-get dest))
(define/provide
(tuple-server-get dest k)
(named-place-channel-put dest (list 'get k))
(named-place-channel-get dest))
(define/provide
(tuple-server-hello dest)
(named-place-channel-put dest (list 'hello)))
(define/provide
(make-tuple-server ch)
(let ()
(define h (make-hash))
(let loop ()
(define msg (place-channel-get ch))
(define (log-to-parent-real
msg
#:severity (severity 'info))
(place-channel-put
ch
(log-message severity msg)))
(syntax-parameterize
((log-to-parent (make-rename-transformer
#'log-to-parent-real)))
(match
msg
((list (list 'set k v) src)
(define result (let () (hash-set! h k v) v))
(place-channel-put src result)
(loop))
((list (list 'get k) src)
(define result (let () (hash-ref h k #f)))
(place-channel-put src result)
(loop))
((list (list 'hello) src)
(define result
(let ()
(printf "Hello from define-cast\n")
(flush-output)))
(loop))))
loop))))
334
Figure 3: Expansion of define-named-remote-server
19 Running and Creating Executables
While developing programs, many Racket programmers use the DrRacket programming
environment. To run a program without the development environment, use racket (for
console-based programs) or gracket (for GUI programs). This chapter mainly explains
how to run racket and gracket.
The gracket executable is the same as racket, but with small adjustments to behave as a
GUI application rather than a console application. For example, gracket by default runs in
interactive mode with a GUI window instead of a console prompt. GUI applications can be
run with plain racket, however.
When racket is run with no command-line arguments (other than confguration options, like
-j), then it starts a REPL with a > prompt:
If any command-line arguments are provided (other than configuration options), add -i or
--repl to re-enable the REPL. For example,
If module-requiring flags appear before -i/--repl, they cancel the automatic requiring of
racket/init. This behavior can be used to initialize the REPL’s environment with a dif-
ferent language. For example,
racket -l racket/base -i
335
starts a REPL using a much smaller initial language (that loads much faster). Beware that
most modules do not provide the basic syntax of Racket, including function-call syntax and
require. For example,
racket -l racket/date -i
produces a REPL that fails for every expression, because racket/date provides only a few
functions, and not the #%top-interaction and #%app bindings that are needed to evaluate
top-level function calls in the REPL.
If a module-requiring flag appears after -i/--repl instead of before it, then the module is
required after racket/init to augment the initial environment. For example,
racket -i -l racket/date
starts a useful REPL with racket/date available in addition to the exports of racket.
If a file argument is supplied to racket before any command-line switch (other than config-
uration options), then the file is required as a module, and (unless -i/--repl is specified),
no REPL is started. For example,
racket hello.rkt
requires the "hello.rkt" module and then exits. Any argument after the file name, flag
or otherwise, is preserved as a command-line argument for use by the required module via
current-command-line-arguments.
If command-line flags are used, then the -u or --require-script flag can be used to ex-
plicitly require a file as a module. The -t or --require flag is similar, except that additional
command-line flags are processed by racket, instead of preserved for the required module.
For example,
requires the "hello.rkt" module, then requires the "goodbye.rkt" module, and then
exits.
The -l or --lib flag is similar to -t/--require, but it requires a module using a lib
module path instead of a file path. For example,
racket -l raco
is the same as running the raco executable with no arguments, since the raco module is the
executable’s main module.
336
Note that if you wanted to pass command-line flags to raco above, you would need to protect
the flags with a --, so that racket doesn’t try to parse them itself:
The -f or --load flag supports loading top-level expressions in a file directly, as opposed
to expressions within a module file. This evaluation is like starting a REPL and typing the
expressions directly, except that the results are not printed. For example,
racket -f hi.rkts
loads "hi.rkts" and exits. Note that load mode is generally a bad idea, for the reasons
explained in §1.4 “A Note to Readers with Lisp/Scheme Experience”; using module mode
is typically better.
The -e or --eval flag accepts an expression to evaluate directly. Unlike file loading, the
result of the expression is printed, as in a REPL. For example,
racket -e '(current-seconds)'
For file loading and expression evaluation, the top-level environment is created in the same
way for interactive mode: racket/init is required unless another module is specified first.
For example,
likely runs faster, because it initializes the environment for evaluation using the smaller
racket/base language, instead of racket/init.
19.2 Scripts
Racket files can be turned into executable scripts on Unix and Mac OS X. On Windows, a
compatibility layer like Cygwin support the same kind of scripts, or scripts can be imple-
mented as batch files.
In a Unix environment (including Linux and Mac OS X), a Racket file can be turned into an
executable script using the shell’s #! convention. The first two characters of the file must be
337
#!; the next character must be either a space or /, and the remainder of the first line must
be a command to execute the script. For some platforms, the total length of the first line is
restricted to 32 characters, and sometimes the space is required. Use #lang
racket/base
The simplest script format uses an absolute path to a racket executable followed by a instead of #lang
racket to produce
module declaration. For example, if racket is installed in "/usr/local/bin", then a file scripts with a faster
containing the following text acts as a “hello world” script: startup time.
#! /usr/local/bin/racket
#lang racket/base
"Hello, world!"
In particular, if the above is put into a file "hello" and the file is made executable (e.g., with
chmod a+x hello), then typing ./hello at the shell prompt produces the output "Hello,
world!".
The above script works because the operating system automatically puts the path to the script
as the argument to the program started by the #! line, and because racket treats a single
non-flag argument as a file containing a module to run.
#! /usr/bin/env racket
#lang racket/base
"Hello, world!"
#! /usr/bin/env racket
#lang racket/base
(printf "Given arguments: ∼s\n"
(current-command-line-arguments))
Usually, then best way to handle command-line arguments is to parse them using the
command-line form provided by racket. The command-line form extracts command-
line arguments from (current-command-line-arguments) by default:
#! /usr/bin/env racket
#lang racket
338
(define greeting
(command-line
#:once-each
[("-v") "Verbose mode" (verbose? #t)]
#:args
(str) str))
(printf "∼a∼a\n"
greeting
(if (verbose?) " to you, too!" ""))
Try running the above script with the --help flag to see what command-line arguments are
allowed by the script.
An even more general trampoline uses /bin/sh plus some lines that are comments in one
language and expressions in the other. This trampoline is more complicated, but it provides
more control over command-line arguments to racket:
#! /bin/sh
#|
exec racket -cu "$0" ${1+"$@"}
|#
#lang racket/base
(printf "This script started slowly, because the use of\n")
(printf "bytecode files has been disabled via -c.\n")
(printf "Given arguments: ∼s\n"
(current-command-line-arguments))
Note that #! starts a line comment in Racket, and #|...|# forms a block comment. Mean-
while, # also starts a shell-script comment, while exec racket aborts the shell script to start
racket. That way, the script file turns out to be valid input to both /bin/sh and racket.
A similar trick can be used to write Racket code in Windows .bat batch files:
; @echo off
; Racket.exe "%∼f0" %*
; exit /b
#lang racket/base
"Hello, world!"
339
19.3 Creating Stand-Alone Executables
For information on creating and distributing executables, see §3 “raco exe: Creating
Stand-Alone Executables” and §4 “raco distribute: Sharing Stand-Alone Executables”
in raco: Racket Command-Line Tools.
340
20 More Libraries
This guide covers only the Racket language and libraries that are documented in The Racket
Reference. The Racket distribution includes many additional libraries.
Racket provides many libraries for graphics and graphical user interfaces (GUIs):
• The racket/draw library provides basic drawing tools, including drawing contexts
such as bitmaps and PostScript files.
See The Racket Drawing Toolkit for more information.
• The racket/gui library provides GUI widgets such as windows, buttons, check-
boxes, and text fields. The library also includes a sophisticated and extensible text
editor.
See The Racket Graphical Interface Toolkit for more information.
Web Applications in Racket describes the Racket web server, which supports servlets imple-
mented in Racket.
341
20.3 Using Foreign Libraries
The Racket Foreign Interface describes tools for using Racket to access libraries that are
normally used by C programs.
Racket Documentation lists documentation for many other installed libraries. Run raco
docs to find documentation for libraries that are installed on your system and specific to
your user account.
342
21 Dialects of Racket and Scheme
We use “Racket” to refer to a specific dialect of the Lisp language, and one that is based on
the Scheme branch of the Lisp family. Despite Racket’s similarity to Scheme, the #lang
prefix on modules is a particular feature of Racket, and programs that start with #lang are
unlikely to run in other implementations of Scheme. At the same time, programs that do not
start with #lang do not work with the default mode of most Racket tools.
“Racket” is not, however, the only dialect of Lisp that is supported by Racket tools. On the
contrary, Racket tools are designed to support multiple dialects of Lisp and even multiple
languages, which allows the Racket tool suite to serve multiple communities. Racket also
gives programmers and researchers the tools they need to explore and create new languages.
“Racket” is more of an idea about programming languages than a language in the usual
sense. Macros can extend a base language (as described in §16 “Macros”), and alternate
parsers can construct an entirely new language from the ground up (as described in §17
“Creating Languages”).
The #lang line that starts a Racket module declares the base language of the module. By
“Racket,” we usually mean #lang followed by the base language racket or racket/base
(of which racket is an extension). The Racket distribution provides additional languages,
including the following:
• typed/racket — like racket, but statically typed; see The Typed Racket Guide
• lazy — like racket/base, but avoids evaluating an expression until its value is
needed; see Lazy Racket
• frtime — changes evaluation in an even more radical way to support reactive pro-
gramming; see FrTime: A Language for Reactive Programs
• scribble/base — a language, which looks more like Latex than Racket, for writing
documentation; see Scribble: The Racket Documentation Tool
Each of these languages is used by starting module with the language name after #lang. For
example, this source of this document starts with #lang scribble/base.
Furthermore, Racket users can define their own languages, as discussed in §17 “Creat-
ing Languages”. Typically, a language name maps to its implementation through a mod-
ule path by adding /lang/reader; for example, the language name scribble/base is
expanded to scribble/base/lang/reader, which is the module that implements the
surface-syntax parser. Some language names act as language loaders; for example, #lang
planet planet-path downloads, installs, and uses a language via PLaneT.
343
21.2 Standards
21.2.1 R5 RS
“R5 RS” stands for The Revised5 Report on the Algorithmic Language Scheme, and it is
currently the most widely implemented Scheme standard.
Racket tools in their default modes do not conform to R5 RS, mainly because Racket tools
generally expect modules, and R5 RS does not define a module system. Typical single-file
R5 RS programs can be converted to Racket programs by prefixing them with #lang r5rs,
but other Scheme systems do not recognize #lang r5rs. The plt-r5rs executable (see §2
“plt-r5rs”) more directly conforms to the R5 RS standard.
Aside from the module system, the syntactic forms and functions of R5 RS and Racket differ.
Only simple R5 RS become Racket programs when prefixed with #lang racket, and rela-
tively few Racket programs become R5 RS programs when a #lang line is removed. Also,
when mixing “R5 RS modules” with Racket modules, beware that R5 RS pairs correspond to
Racket mutable pairs (as constructed with mcons).
See R5RS: Legacy Scheme for more information about running R5 RS programs with Racket.
21.2.2 R6 RS
“R6 RS” stands for The Revised6 Report on the Algorithmic Language Scheme, which ex-
tends R5 RS with a module system that is similar to the Racket module system.
See R6RS: Scheme for more information about running R6 RS programs with Racket.
21.3 Teaching
The How to Design Programs textbook relies on pedagogic variants of Racket that smooth
the introduction of programming concepts for new programmers. The languages are docu-
mented in How to Design Programs Languages.
344
The How to Design Programs languages are typically not used with #lang prefixes, but
are instead used within DrRacket by selecting the language from the Choose Language...
dialog.
345
22 Command-Line Tools and Your Editor of Choice
Although DrRacket is the easiest way for most people to start with Racket, many Racketeers
prefer command-line tools and other text editors. The Racket distribution includes several
command-line tools, and popular editors include or support packages to make them work
well with Racket.
Racket provides, as part of its standard distribution, a number of command-line tools that
can make racketeering more pleasant.
The raco (short for “Racket command”) program provides a command-line interface to
many additional tools for compiling Racket programs and maintaining a Racket installation.
346
22.1.2 Interactive evaluation: XREPL
The Racket distribution includes XREPL (eXtended REPL), which provides everything you
expect from a modern interactive environment. For example, XREPL provides an ,enter
command to have a REPL that runs in the context of a given module, and an ,edit command
to invoke your editor (as specified by the EDITOR environment variable) on the file you
entered. A ,drracket command makes it easy to use your favorite editor to write code, and
still have DrRacket at hand to try things out.
The "meta" collection is only available in the Racket Full distribution. The completion
scripts are also available online.
22.2 Emacs
Emacs has long been a favorite among Lispers and Schemers, and is popular among Racke-
teers as well.
347
• Emacs ships with a major mode for Scheme, scheme-mode, that while not as feature-
ful as the above options, but works reasonably well for editing Racket code. However,
this mode does not provide support for Racket-specific forms.
• No Racket program is complete without documentation. Scribble support for emacs
is available with Neil Van Dyke’s Scribble Mode.
In addition, texinfo-mode (included with GNU Emacs) and plain text modes work
well when editing Scribble documents. The Racket major modes above are not really
suited to this task, given how different Scribble’s syntax is from Racket’s.
22.3 Vim
Many distributions of Vim ship with support for Scheme, which will mostly work for Racket.
You can enable filetype detection of Racket files as Scheme with the following:
if has("autocmd")
au BufReadPost *.rkt,*.rktl set filetype=scheme
endif
Alternatively, you can use the vim-racket plugin to enable auto-detection, indentation, and
syntax highlighting specifically for Racket files. Using the plugin is the easiest method, but if
348
you would like to roll your own settings or override settings from the plugin, add something
like the following to your ".vimrc" file:
if has("autocmd")
au BufReadPost *.rkt,*.rktl set filetype=racket
au filetype racket set lisp
au filetype racket set autoindent
endif
However, if you take this path you may need to do more work when installing plugins be-
cause many Lisp-related plugins and scripts for vim are not aware of Racket. You can also set
these conditional commands in a "scheme.vim" or "racket.vim" file in the "ftplugin"
subdirectory of your vim folder.
Most installations of vim will automatically have useful defaults enabled, but if your instal-
lation does not, you will want to set at least the following in your ".vimrc" file:
" No tabs!
set expandtab
Indentation
You can enable indentation for Racket by setting both the lisp and autoindent options
in Vim. However, the indentation is limited and not as complete as what you can get in
Emacs. You can also use Dorai Sitaram’s scmindent for better indentation of Racket code.
The instructions on how to use the indenter are available on the website.
If you use the built-in indenter, you can customize it by setting how to indent certain key-
words. The vim-racket plugin mentioned above sets some default keywords for you. You
can add keywords yourself in your ".vimrc" file like this:
" By default vim will indent arguments after the function name
" but sometimes you want to only indent by 2 spaces similar to
" how DrRacket indents define. Set the `lispwords' variable to
" add function names that should have this type of indenting.
set lispwords+=public-method,override-method,private-method,syntax-
case,syntax-rules
set lispwords+=..more..
349
Highlighting
The Rainbow Parenthesis script for vim can be useful for more visible parenthesis matching.
Syntax highlighting for Scheme is shipped with vim on many platforms, which will work for
the most part with Racket. The vim-racket script provides good default highlighting settings
for you.
Structured Editing
The Slimv plugin has a paredit mode that works like paredit in Emacs. However, the plugin
is not aware of Racket. You can either set vim to treat Racket as Scheme files or you can
modify the paredit script to load on ".rkt" files.
Scribble
Vim support for writing scribble documents is provided by the scribble.vim plugin.
Miscellaneous
If you are installing many vim plugins (not necessary specific to Racket), we recommend
using a plugin that will make loading other plugins easier. Pathogen is one plugin that
does this; using it, you can install new plugins by extracting them to subdirectories in the
"bundle" folder of your Vim installation.
350
Bibliography
351
Index box, 59
Boxes, 59
#!, 337 bracketed character class, 193
.bat, 339 Breaking an Iteration, 219
.zo, 346 Built-In Datatypes, 42
3m, 323 byte, 48
A Customer-Manager Component, 167 byte string, 49
A Dictionary, 172 Bytes and Byte Strings, 48
A Note to Readers with Lisp/Scheme Expe- Bytes, Characters, and Encodings, 187
rience, 17 call-by-reference, 273
A Parameteric (Simple) Stack, 169 CGC, 323
A Queue, 174 Chaining Tests: cond, 83
Abbreviating quote with ', 39 character, 45
aborts, 207 character class, 193
Abstract Contracts using #:exists and Characters, 45
#:∃, 165
Characters and Character Classes, 193
accessor, 101
Checking Properties of Data Structures, 163
Adding Collections, 116
Checking State Changes, 151
Adding Contracts to Signatures, 254
Class Contracts, 239
Adding Contracts to Units, 256
Classes and Objects, 226
Additional Examples, 166
cloister, 199
Alternation, 200
Cloisters, 199
An Aside on Indenting Code, 20
closures, 324
An Extended Example, 203
Clustering, 196
And More, 342
Clusters, 196
Anonymous Functions with lambda, 26
code inspectors, 294
any and any/c, 138
collection, 115
Argument and Result Dependencies, 148
Combining Tests: and and or, 82
Arity-Sensitive Functions: case-lambda,
Command-Line Tools, 346
71
Command-Line Tools and Your Editor of
arms, 292
Choice, 346
assertions, 192
comments, 19
Assignment and Redefinition, 132
Compilation and Configuration: raco, 346
Assignment: set!, 88
Compile and Run-Time Phases, 281
attached, 263
complex, 44
backreference, 197
components, 246
Backreferences, 197
composable continuations, 209
Backtracking, 201
Conditionals, 81
backtracking, 201
Conditionals with if, and, or, and cond, 22
Basic Assertions, 192
conservative garbage collector, 324
benchmarking, 318
constructor, 101
blocking, 327
constructor guard, 110
Booleans, 42
352
continuation, 208 disarm, 292
Continuations, 208 Dissecting a contract error message, 144
contract combinator, 138 Distributed Places, 331
Contract Messages with “???”, 142 domain, 137
Contract Violations, 135 dye pack, 292
Contracts, 135 Dynamic Binding: parameterize, 97
Contracts and Boundaries, 135 Effects After: begin0, 86
Contracts and eq?, 176 Effects Before: begin, 85
Contracts for case-lambda, 148 Effects If...: when and unless, 87
Contracts for Units, 254 Emacs, 347
Contracts on Functions in General, 144 eval, 259
Contracts on Higher-order Functions, 142 Evaluation Order and Arity, 64
Contracts on Structures, 161 exception, 205
Contracts: A Thorough Example, 155 Exceptions, 205
Controlling the Scope of External Names, Exceptions and Control, 205
231 Exists Contracts and Predicates, 177
Copying and Update, 102 expander, 40
Creating and Installing Namespaces, 263 expands, 268
Creating Executables, 16 Experimenting with Contracts and Modules,
Creating Languages, 297 136
Creating Stand-Alone Executables, 340 Exports: provide, 131
current continuation, 208 Expressions and Definitions, 61
current namespace, 260 Extended Example: Call-by-Reference
Curried Function Shorthand, 73 Functions, 273
Datatypes and Serialization, 185 External Class Contracts, 239
Declaring a Rest Argument, 67 Final, Augment, and Inner, 231
Declaring Keyword Arguments, 69 First-Class Units, 250
Declaring Optional Arguments, 68 Fixed but Statically Unknown Arities, 154
Default Ports, 182 fixnum, 322
default prompt tag, 207 Fixnum and Flonum Optimizations, 322
define-syntax and syntax-rules, 270 flat named contracts, 143
define-syntax-rule, 268 flonum, 322
Defining new #lang Languages, 306 for and for*, 212
Defining Recursive Contracts, 178 for/and and for/or, 216
Definitions, 19 for/first and for/last, 216
Definitions and Interactions, 15 for/fold and for*/fold, 217
definitions area, 15 for/list and for*/list, 214
Definitions: define, 72 for/vector and for*/vector, 215
delimited continuations, 209 Function Calls (Procedure Applications), 21
Designating a #lang Language, 307 Function Calls (Procedure Applications), 63
destructing bind, 225 Function Calls, Again, 25
Dialects of Racket and Scheme, 343 Function Shorthand, 72
353
Function-Call Optimizations, 320 keyword, 52
functional update, 102 Keyword Arguments, 146
Functions (Procedures): lambda, 66 Keyword Arguments, 64
General Macro Transformers, 276 Keywords, 52
General Phase Levels, 284 letrec Performance, 322
generational garbage collector, 323 Lexical Scope, 269
Gotchas, 176 Library Collections, 115
Graphics and GUIs, 341 link, 250
greedy, 196 Linking Units, 249
Guarantees for a Specific Value, 161 list, 53
Guarantees for All Values, 161 List Iteration from Scratch, 31
Guidelines for Using Assignment, 89 Lists and Racket Syntax, 40
hash table, 57 Lists, Iteration, and Recursion, 29
Hash Tables, 57 Load Mode, 337
I/O Patterns, 187 Local Binding, 77
identifier macro, 272 Local Binding with define, let, and let*,
Identifier Macros, 272 28
identifier syntax object, 277 Local Scopes, 260
Identifiers, 21 Lookahead, 202
Identifiers and Binding, 62 Lookbehind, 202
Implicit Form Bindings, 298 Looking Ahead and Behind, 201
Imports: require, 128 macro, 268
index pairs, 190 macro pattern variables, 268
Inherit and Super in Traits, 237 macro transformer, 276
Initialization Arguments, 229 macro-generating macro, 273
Input and Output, 180 Macro-Generating Macros, 273
Installing a Language, 310 Macros, 268
instantiates, 128 Main and Test Submodules, 121
integer, 44 main submodule, 122
Interacting with Racket, 15 Major Modes, 347
Interactive evaluation: XREPL, 347 Manipulating Namespaces, 262
Interactive Mode, 335 Matching Regexp Patterns, 190
Interfaces, 230 Matching Sequences, 271
Internal and External Names, 230 Memory Management, 323
Internal Class Contracts, 242 meta-compile phase level, 283
Internal Definitions, 76 metacharacters, 189
invoked, 246 metasequences, 189
Invoking Units, 248 Methods, 227
Iteration Performance, 221 Minor Modes, 348
Iterations and Comprehensions, 210 mixin, 233
JIT, 319 Mixing Patterns and Expressions: syntax-
just-in-time, 319 case, 278
354
Mixing set! and contract-out, 178 pair, 53
Mixins, 233 Pairs and Lists, 53
Mixins and Interfaces, 234 Pairs, Lists, and Racket Syntax, 36
Module Basics, 113 Parallel Binding: let, 77
module language, 297 Parallelism with Futures, 324
Module Languages, 297 Parallelism with Places, 329
Module Mode, 336 parameter, 97
module path, 123 Parameterized Mixins, 235
Module Paths, 123 Pattern Matching, 223
Module Syntax, 117 pattern variables, 223
Module-Handling Configuration, 313 pattern-based macro, 268
Modules, 113 Pattern-Based Macros, 268
Modules and Performance, 319 Performance, 318
More Libraries, 341 Performance in DrRacket, 318
More Rackets, 343 phase, 284
More Structure Type Options, 108 phase level, 285
multi-line mode, 199 phase level -1, 284
Multiple Result Values, 152 phase level 2, 283
Multiple Values and define-values, 75 Phases and Bindings, 284
Multiple Values: let-values, let*- Phases and Modules, 286
values, letrec-values, 81 place, 329
Multiple Values: set!-values, 91 place channel, 330
Multiple-Valued Sequences, 218 port, 180
mutable pair, 55 POSIX character class, 194
Mutation and Performance, 321 POSIX character classes, 194
mutator, 109 Predefined List Loops, 30
Named let, 80 predicate, 101
namespace, 260 prefab, 106
Namespaces, 260 Prefab Structure Types, 106
Namespaces and Modules, 261 Programmer-Defined Datatypes, 101
non-capturing, 199 prompt, 207
Non-capturing Clusters, 199 prompt tag, 207
non-greedy, 196 Prompts and Aborts, 207
Notation, 61 property, 111
number, 42 protected, 296
Numbers, 42 Protected Exports, 296
opaque, 103 protected method, 231
Opaque versus Transparent Structure Types, Quantifiers, 195
103 quantifiers, 195
Optional Arguments, 145 Quasiquoting: quasiquote and `, 94
Optional Keyword Arguments, 147 Quoting Pairs and Symbols with quote, 37
Organizing Modules, 114 Quoting: quote and ', 92
355
R5 RS, 344 194
R6 RS, 344 Source Locations, 303
Racket Essentials, 18 Source-Handling Configuration, 311
racket/exists, 177 speed, 318
range, 137 Standards, 344
rational, 44 string, 47
reader, 40 Strings (Unicode), 47
Reader Extensions, 301 Structure Comparisons, 104
Reading and Writing Racket Data, 183 Structure Subtypes, 102
readtable, 305 structure type descriptor, 102
Readtables, 305 Structure Type Generativity, 105
real, 44 Styles of ->, 138
Recursion versus Iteration, 35 subcluster, 199
Recursive Binding: letrec, 79 submatch, 196
Reflection and Dynamic Evaluation, 259 submodule, 120
regexp, 189 Submodules, 120
Regular Expressions, 189 subpattern, 196
REPL, 15 symbol, 50
Rest Arguments, 146 Symbols, 50
Rolling Your Own Contracts, 139 synchronized, 327
Running and Creating Executables, 335 Syntax Objects, 276
Running racket and gracket, 335 syntax objects, 276
S-expression, 301 Syntax Taints, 291
Scripting Evaluation and Using load, 265 tail position, 34
Scripts, 337 Tail Recursion, 33
Sequence Constructors, 211 tainted, 292
Sequencing, 85 Tainting Modes, 293
Sequential Binding: let*, 78 Taints and Code Inspectors, 294
serialization, 185 Teaching, 344
shadows, 63 template, 268
Sharing Data and Code Across Namespaces, template phase level, 284
264 text string, 189
Shell completion, 347 The #lang Shorthand, 119
signatures, 246 The apply Function, 65
Signatures and Units, 246 The Bytecode and Just-in-Time (JIT) Com-
Simple Branching: if, 82 pilers, 318
Simple Contracts on Functions, 137 The mixin Form, 234
Simple Definitions and Expressions, 18 The module Form, 118
Simple Dispatch: case, 96 The Racket Guide, 1
Simple Structure Types: struct, 101 The trait Form, 238
Simple Values, 18 The Web Server, 341
Some Frequently Used Character Classes, Traits, 236
356
Traits as Sets of Mixins, 236
transformer, 268
transformer binding, 276
transparent, 103
Unchecked, Unsafe Operations, 323
unit versus module, 258
Units, 246
Units (Components), 246
Unix Scripts, 337
Using #lang reader, 307
Using #lang s-exp, 300
Using #lang s-exp syntax/module-
reader, 309
Using Foreign Libraries, 342
Varieties of Ports, 180
vector, 56
Vectors, 56
Vim, 348
Void and Undefined, 59
Welcome to Racket, 14
Whole-module Signatures and Units, 253
Windows Batch Files, 339
with-syntax and generate-
temporaries, 280
Writing Regexp Patterns, 189
357