The list is the fundamental data structure of Racket. A list is a sequence of values. A list can contain any kind of value, including other lists. A list can contain any number of values. If a list has zero values, it’s called the empty list.
1 2 3 4 | () ; empty list (1 2 3) ; three numbers ("a" "b" "c" "d") ; four strings (1 2 3 ("a" "b" "c" (4 5 6))) ; list with sublists |
Any time you put values between parentheses, you’re making a list. By default, square and curly brackets work the same way as parentheses, so these lists are the same:
1 2 3 | (1 2 3 ("a" "b" "c" (4 5 6))) [1 2 3 ["a" "b" "c" [4 5 6]]] {1 2 3 ["a" "b" "c" (4 5 6)]} |
In practice, parentheses are preferred, and square and curly brackets are reserved for special situations where they improve readability, for instance the variables introduced at the top of a let:
If you type a list in a Racket program, by default it will be interpreted as Racket code:
1 2 3 4 | (* 42 58) ; prints 2436 (1 2 3) ; error: 1 is not a function () ; error: missing procedure (a b c) ; error: `a` is not defined |
To make a list of values that will be evaluated as data, not code, use the list function:
Alternatively, you can make a special kind of list with quote, called a datum. quote can be used as a function. But the idiomatic way to use it is by adding a ' prefix to any expression. Below, some datums made with quote, and the equivalent list notation on the right:
1 2 3 4 5 | (quote (* 42 58)) ; (list '* '42 '58) '(* 42 58) ; (list '* '42 '58) '(1 2 3) ; (list '1 '2 '3) '() ; (list) '(a b c) ; (list 'a 'b 'c) |
Caution: depending on the input, list and quote may or may not produce the same output list. For instance, Racket deems numbers, strings, and Booleans to be “self-quoting”—meaning, they’re already in datum form—so they’re not changed by quote. For these values, list and quote (and its equivalent, the ' prefix) can be used interchangeably:
But other values, like variables and expressions, are not self-quoting, so list and quote produce different results:
1 2 3 4 5 6 |
When you use list, a subexpression like (* 6 7) is first evaluated as 42 before it’s put in the list. But when you use quote, that subexpression is just treated as a sublist of datums.
For Racket newcomers, list tends to be the less confusing choice. Later, you’ll come to appreciate the ' shorthand when typing longer lists of self-quoting values. These two lists are the same:
A variable that holds a list is often named with a plural ending (like s) to signal multiple values. Following that idea, a variable that holds a list of lists can be named with a double-plural ending (though triple- may be pushing it):
Racket prints lists using a leading quotation mark ' followed by the simplest textual representation of each value.
Self-quoting values are printed the same way they’re typed, so these lists:
Are printed like so:
1 2 | '(1 2 3 ((a b c) "d" "e" "f")) '(1 2 3 ((a b c) "d" "e" "f")) |
The way a list is printed doesn’t depend on how it’s constructed, only on what’s in it. Even though the first list uses list and the second uses quote, they print the same way.
Also, a printed list of self-quoting values is identical to the '-prefixed list form, so you could copy this output and paste it back into a program as code.
By contrast, values in a list that are not self-quoting:
Will be printed with a textual approximation:
1 | '(#<procedure:+> #<procedure:expt>) |
Textual representations of these non-self-quoting values cannot be repurposed as program code, as you find when you paste the last result back into the program window:
1 | '(#<procedure:+> #<procedure:expt>) ; error: bad syntax |
Lists with a mixture of self-quoting values and others print accordingly:
1 2 | '(1 2 ("a" "b") #<procedure:+>) '(1 2 ("a" "b") #<procedure:+>) |
Finally, keep in mind that the leading quotation mark on a printed list and the parentheses delimiting its edges aren’t intrinsically part of the list, any more than the quotation marks printed "around a string" or the leading zero printed for a number like 0.1234. These are just notational conveniences used when reducing these values to text. In DrRacket, you can change the way lists are printed with Language → Choose Language ... → Output Style.
Between list and quote is quasiquote. As the name implies, by default it works like quote, but it also allows you to interpolate expressions that are evaluated normally (as they would be with list).
Like quote, though quasiquote can be invoked as a function, it’s more commonly notated with a prefix, this time the backtick `. To interpolate a single value, use unquote, which is usually written as a comma prefix , followed by the expression:
1 2 3 | (define x 42) '(41 x 43) ; prints '(41 x 43) `(41 ,x 43) ; prints '(41 42 43) |
To interpolate a list of multiple values, use unquote-splicing, which is usually written as a comma followed by an at sign ,@ followed by the variable. The unquote-splicing function merges the sublist with the surrounding list:
If you use unquote with a sublist, the sublist will remain nested:
Lists are ubiquitous in Racket, thus many functions consume or produce lists. A handful are worth committing to memory because they’re so common.
list?: test if something is a list.
length: get the number of elements in a list.
flatten: squish nested sublists into a single list. + CS pros: “squish” = a pre-order depth-first traversal.
1 | (flatten '(1 (2 3 (4 5 (6) 7) 8 9))) ; '(1 2 3 4 5 6 7 8 9) |
apply: append a list of values to the argument list for a function.
map: apply a function to every value in a list, and get back a list of return values. The input and output lists are always the same length. If the function accepts multiple values, then multiple lists must be provided, of the same length.
for-each: like map, apply a function to every value of a list; unlike map, ignore the return values. This is handy when the function is being used for its side effect, not for its return value.
filter: take the values from a list that match a predicate function, and discard the others. The most common way of shortening a list.
cons: insert a value at the front of a list.
1 | (cons 1 '(2 3 4)) ; '(1 2 3 4) |
append: join multiple lists into a single list.
1 | (append '(1 2 3) '(4 5 6) '(7 8 9)) ; '(1 2 3 4 5 6 7 8 9) |
cdr or rest: get the tail of a list after the first value, which is always a list (though possibly empty).
car and cdr are the inverse of cons, so this identity is true for every non-empty list:
For the origin of these three oddly-named functions, see pairs.
range: make a list of numbers.
As a data structure, lists are designed to cooperate well with recursive-style functions that consume the elements of the list in sequence. The idea is that on each pass, the function only transforms the first element of the list, and recurses on the rest until it’s empty, and the results are reassembled into a list with cons:
List functions like map and filter offer a higher-level interface to this same recursion logic.
See also recursion.
Because lists are made of linked pairs, they’re optimized for sequential access, not random access. Though you can use list-ref to retrieve an arbitrary element from a list, it works by starting at the front of the list and traversing to the requested element. For small lists, that’s no big deal. For larger lists, it can be slow. At that point, probably you’ll be happier with a vector. See data structures.
Pairs and Lists in the Racket Guide
Pairs, Lists, and Racket Syntax in the Racket Guide
The Racket architects explain why lists print as they do on the Racket mailing list