Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 11

Quoting Code as Data

Recommended resources

Introduction

Welcome back! In our previous lesson, we explored homoiconicity—the powerful Lisp concept that code and data share the same structure: the S-expression. We discussed how the Lisp interpreter works in two stages: the Reader turns text into a structured list, and the Evaluator executes that list as code. You saw that this separation is the key to Lisp's extensibility, as it allows us to manipulate code as if it were data.

Today, we're moving from the "why" to the "how." The central question is: how do we tell the Evaluator to pause and not execute an S-expression? This lesson focuses on the primary tool for that job. Your learning outcome is to use quote to prevent evaluation and treat code as data. This is the first practical step in harnessing the power of homoiconicity, and a concept you'll use constantly when writing Elisp.


1. The Default: Eager Evaluation

Let's start by reinforcing what we know. By default, the Lisp evaluator is "eager." When it sees a list, it assumes the first element is a function it must execute.

Open your *scratch* buffer in Emacs. Type the following expression and evaluate it (using C-x C-e with your cursor after the expression):

(+ 10 20)

As expected, the minibuffer shows the result 30. The evaluator saw a list, identified + as a function, evaluated the arguments 10 and 20 (which, as numbers, evaluate to themselves), and applied the function to them.

Now, what if our goal wasn't to get the sum, but to inspect the expression (+ 10 20) itself? For example, what if we wanted to extract the function symbol + from that list?

Let's try using a function you'll learn more about later, car, which returns the first element of a list. Try evaluating this:

(car (+ 10 20))

You'll get an error: wrong-type-argument listp 30.

Why? Because the evaluator follows its rules strictly. Before executing car, it first evaluates its argument, (+ 10 20). That argument evaluates to 30. The expression effectively becomes (car 30). Since 30 is a number, not a list, car fails.

We need a way to tell the evaluator: "Stop! Look at the list (+ 10 20) itself. Don't execute it."


2. quote: The "Do Not Evaluate" Command

The tool for this is a special form called quote. Its entire purpose is to prevent the evaluation of its argument, returning it exactly as written.

To see quote in action, let's watch a short, practical demonstration.

Learn Emacs Lisp in 30 Minutes

This clip from Gavin Freeborn's 'Learn Emacs Lisp in 30 Minutes' clearly demonstrates the effect of quote and introduces its common shorthand.

Watch from 07:01 to 09:34. The video explains several data types but pay close attention to the section on quote. Notice how it transforms an expression that would normally be calculated into a simple list.

As the video showed, you can write quote in two ways:

  1. The full form: (quote an-expression)
  2. The shorthand: 'an-expression

The single-quote shorthand (') is used almost universally in Lisp code. It's concise and readable. The Lisp Reader sees ' and automatically converts 'something into (quote something) before the Evaluator even sees it.

Now, let's solve our car problem from before. In your *scratch* buffer, evaluate this expression:

(car '(+ 10 20))

The result in the minibuffer is +. It worked! Here’s the step-by-step breakdown:

  1. The evaluator sees the expression (car '(+ 10 20)).
  2. It prepares to call the car function, so it must first evaluate its argument, '(+ 10 20).
  3. The ' tells the evaluator: "Do not evaluate (+ 10 20)."
  4. The argument is therefore the literal list (+ 10 20).
  5. The expression becomes (car <the-list-(+ 10 20)>).
  6. car takes the first element of that list, which is the symbol +.

This visual summary captures the core idea perfectly.

Control of LISP Evaluation: quote & eval
This slide illustrates the fundamental difference in evaluation. An S-expression like `(+ 2 3)` evaluates to a result, `5`. A quoted expression like `'(+ 2 3)` evaluates to the list structure itself, `(+ 2 3)`, effectively treating the code as data.

3. Quoting Beyond Expressions: Symbols and Lists

quote is essential for handling more than just function calls. It's fundamental for working with symbols and creating lists of data.

To understand this better, let's read a short but very clear article by Protesilaos Stavrou, a well-known Emacs contributor.

Emacs Lisp Elements | Protesilaos Stavrou

This section from 'Emacs Lisp Elements' explains the distinction between a list as a function call and a list as data, highlighting the critical role of quoting.

Please read the section '6. Symbols, balanced expressions, and quoting'. Focus on the two bullet points: 'The list as a function call' and 'The list as data'. The explanation of why (car '("Protesilaos" ...)) needs a quote is particularly relevant. Also, note the discussion on self-evaluating types vs. symbols.

This reading brings up two critical points:

A. Symbols as Data

An unquoted symbol is treated as a variable, and the evaluator tries to look up its value.
Try evaluating this in your *scratch* buffer:

my-symbol

You'll get a void-variable error because my-symbol has no value. But what if you wanted to work with the symbol my-symbol itself? You quote it.

'my-symbol

This evaluates to the symbol my-symbol. It is now data. You can pass it to functions, put it in a list, and manipulate it, all because quote prevented the evaluator from trying to look up its value.

B. Self-Evaluating Types

As the article mentions, some data types don't need quoting because they evaluate to themselves. These include:

  • Numbers: 42 evaluates to 42.
  • Strings: "hello" evaluates to "hello".
  • t and nil: The boolean values for true and false.

This is why (+ 1 2) works without quoting the numbers. The symbol + needs to be evaluated to find its function definition, but the numbers 1 and 2 evaluate to themselves.

This leads to a common pattern for creating a list of mixed data:

;; Create a list containing a number, a string, and a symbol
'(123 "my-string" another-symbol)

Without the initial quote, Elisp would try to call a function named 123, which would fail. With the quote, you get a simple list containing three data elements.


4. quote as a Special Form

You might have noticed that quote behaves differently from a regular function like + or car. A regular function always evaluates all its arguments before it runs. quote does not—in fact, its entire purpose is to not evaluate its argument.

This is because quote is not a function; it is a special form. Special forms are a small set of built-in Elisp constructs that have their own unique rules for evaluation. They provide the fundamental logic and structure of the language that functions build upon.

Let's read a formal description to solidify this distinction.

[PDF] Introduction to Lisp and Emacs

This PDF provides a more academic perspective, defining special forms and explaining precisely how quote fits into that category.

First, read section '3 Special Forms' (page 11) to understand that special forms have unique evaluation rules. Then, read section '3.3 The quote Special Form' (page 13), which describes the evaluation rule for quote as simply returning its unevaluated argument.

The key takeaway is that when the Lisp evaluator sees a list, it first checks if the first element is a special form keyword (like quote, if, let, defun). If it is, it uses the unique evaluation rule for that special form. If not, it assumes it's a regular function call and evaluates all the arguments.


Conclusion

In this lesson, you have gained control over the Lisp evaluator. By understanding and using quote, you can now cleanly separate code from data, which is the practical application of homoiconicity.

Key Takeaways:

  • By default, the Lisp evaluator tries to evaluate every part of an S-expression.
  • The quote special form, and its shorthand ', is the explicit instruction to the evaluator to prevent evaluation.
  • quote allows you to treat what would be executable code (like (+ 1 2)) as a simple list data structure.
  • It is also used to treat symbols as data, preventing the evaluator from interpreting them as variables to be looked up.
  • quote is a special form, not a function, because it has unique evaluation rules—specifically, it does not evaluate its argument.

Preview of the Next Lesson:

We've established that quote is a "special form." In the next lesson, we will deepen this understanding by formally contrasting special forms with regular functions. You'll learn why this distinction is crucial for building control structures and understanding how Elisp really works. We will then continue our journey by learning about eval, the counterpart to quote, which allows you to take data and explicitly ask the evaluator to execute it as code.