cadence’s website.

Some changes will be applied after reloading.
Some changes will be applied after reloading.

Explaining Lisp's quoting without getting tangled

Quoting in Lisp is a very important concept in programs that deal with data structures. Here's the concept explained without excessive detail.

This page specifically uses the Racket dialect of Lisp, but these examples are general enough that they should apply to any kind of Lisp.

Definitions

You don't need to memorise these right now, you can always come back and check them later for clarification.

  • value - something like a number, a string, or a symbol. values are data.
  • list - a one-dimensional list of values (can also include nested lists). lists are data.
  • variable - a variable stands for a value, but the variable itself is not a value. variables are not data (but their values are).
  • symbol - a symbol looks like a variable name but it has ' before it. symbols are data.
  • sexp - stands for s-expression. a sexp is anything between parentheses. to be more specific, it starts with an open parenthesis and continues until the matching closing parenthesis. there may be nested sexps inside it. sexps might be data or might not be - you'll see.
  • word - this isn't Lisp terminology, this a term that I made up to represent a sequence of letters that appears within a program.

It's okay if these don't make sense right now, because the rest of this page will serve as examples for all of these.

Sexps can be code

(define x 42)

This can be executed as code. The first word inside the opening parenthesis is the function to call, and the other words are its arguments.

Here, x is a variable, 42 is a value, and (define x 42) is a sexp. (define x 42) is not a value because it will be executed as code.

Constructing lists

The function list creates a list out of its arguments:

(displayln (list 39 40 41))

Try writing this as a program and executing it. The output area will show the result (39 40 41). The result displayed in the output area is a list (and also a value, and also a sexp).

Quoting lists

Rather than constructing lists, they can be directly represented in the program by writing the list with a quote mark ' before it:

(displayln '(39 40 41))

Try writing this as a program and executing it. The output area will show the list (39 40 41) which is the same as before.

Since the quote mark ' affects the entire sexp that follows, you can quote nested lists too, using just a single quote mark:

(displayln '(39 40 (41 42) 43))

If you didn't write the quote, the interpreter would treat this sexp as a program to execute. It would try to call 41 as a function, and then try to call 39 as a function. Numbers aren't functions, so you'll get an error if you try.

(displayln (append '(1) (list 2)))

The quote only applies until the end of the sexp. It applies to '(1) but does not apply to (list 2).

Context: displayln

Up until now, we've been using displayln to display the values in the output area.

From now on, we're just going to write the values directly. One difference in doing this is that when not using displayln the output area will also include a quote for any printed list.

(list 39 40 41) ; example one
'(39 40 41) ; example two

When each of these is evaluated, the output area shows '(39 40 41), with a quote mark. This fact isn't particularly significant, I just want to make sure we're on the same page.

Quoting other things

Quoting a word results in the concept of a "symbol" that was alluded to earlier.

Executing this program gives the symbol 'x in the output area:

'x

Conceptually, symbols are just arbitrary values. One use for them is like enums from other programming languages.

Now that you know what a symbol is, I can show you that entire sexps can be quoted too:

'(39 40 41 x 43)

Since the quote mark ' affects the entire sexp, the x here is quoted too, and becomes a symbol. The result displayed in the output area is '(39 40 41 x 43). x is not evaluated as a variable, because it isn't a variable. Because it is quoted, it is a symbol, and symbols are just values.

Observe:

(require racket/list)
(second '(39 40 41 x 43)) ; -> 40
(fourth '(39 40 41 x 43)) ; -> 'x

So you can use this for data structures

<p>Welcome to my <b>cool website!</b></p>

X-expressions are a Lisp-y representation of XML. They represent XML as list structures, which can then be manipulated with the usual sexp-related functions like list and car. It's easiest to explain with an example:

'(p "Welcome to my " (b "cool website!"))

The quote mark ' at the start is required because 'p and 'b shouldn't be called as functions. This sexp is a store of data, not a program to be executed. 'p and 'b are actually symbols, and in this case they represent the XML tag name.

A practical example of manipulating lists

The <b> tag is deprecated in HTML 5, so let's replace it with the semantic <strong> instead.

In other programming languages, you might expect to use an object-oriented XML parser to do the work, but quoting and the x-expression notation lets us take a different approach in Lisp.

(define old '(p "Welcome to my " (b "cool website!")))
(define (replace-strong sexp)
  (cond [(symbol? sexp) (if (eq? sexp 'b) 'strong sexp)] ; recursion target: replace 'b with 'strong
        [(pair? sexp) (cons (replace-strong (car sexp)) (replace-strong (cdr sexp)))] ; recursion: reached a cons cell, replace its contents
        [#t sexp] ; don't touch other types like strings
        ))
(replace-strong old) ; -> '(p "Welcome to my " (strong "cool website!"))

DON'T PANIC if this example is beyond you. If you understand it, awesome! If you don't understand it, you're not missing out.

Quasiquote and unquote

Touching on the example from earlier:

'(39 40 41 x 43)

What if you wanted 'x to actually be used as a variable, not a symbol? What if you did want to create the list '(39 40 41 42 43)? Without quoting, this can be done as follows:

(list 39 40 41 x 43)

But this can get messy if the data structure is complex, with several nested lists.

The quasiquote feature allows this in a compact notation. The quasiquote character, also known as backquote or backtick ` acts just like the normal quote ' most of the time:

`(39 40 41 x 43)

But using a quasiquote enables two additional features. Using a comma, you can unquote a specific value anywhere in the tree, such as inside nested lists:

`(39 40 41 ,x 43) ; -> '(39 40 41 42 43)
`(39 40 (41 (,x)) 43) ; -> '(39 40 (41 (42)) 43)

Quasiquote is often much easier and less messy than the alternative:

(list 39 40 (list 41 (list x)) 43) ; -> '(39 40 (41 (42)) 43)

The second additional feature

You can splice lists into other lists using ,@ inside a quasiquoted list. Wow, that was a lot of jargon. Check out the example:

(define y '(5 6 7 8))
`(4 ,y 9) ; -> (4 (5 6 7 8) 9)
`(4 ,@y 9) ; -> (4 5 6 7 8 9)

Using unquote , puts the value directly into the other list. Using unquote-splicing ,@ puts each list element into the other list, flattening them together.

Need more?

If you want to read a longer and more thorough explanation, an excellent option is available in the How to Design Programs book.

If you want to learn about how code and data are the same structures and how this naturally connects into macros, see CSE341 Lecture Notes 14 and then Macros in the Common Lisp Cookbook.

If you want to learn more Lisp basics, check Lisp Quickstart - Learning Lisp Fast for the short version and The Racket Guide for the long version.

If you want to learn how to design programs, read the How to Design Programs book for beginners.

Did you try the examples?

Hopefully this guide was an appropriate length to get you get to grips with quoting. Knowing you, you just read through this whole thing without trying the code examples in your editor, and that's okay! I designed this guide so that it should make sense just reading it, but I really really do recommend pasting the examples into your editor if you want to explore them and deepen your understanding.

Okay, that's the end. See ya!

— Cadence

A seal on a cushion spinning a globe on its nose.
Another seal. They are friends!