Backquote-Style Patterns

This subsection describes backquote-style patterns, a set of builtin patterns that eases structural matching. For background, see Pattern-Matching Conditional.

Backquote-style patterns are a powerful set of pcase pattern extensions (created using pcase-defmacro) that make it easy to match expval against specifications of its structure.

For example, to match expval that must be a list of two elements whose first element is a specific string and the second element is any value, you can write a core pattern:

(and (pred listp)
     ls
     (guard (= 2 (length ls)))
     (guard (string= "first" (car ls)))
     (let second-elem (cadr ls)))

or you can write the equivalent backquote-style pattern:

`("first" ,second-elem)

The backquote-style pattern is more concise, resembles the structure of expval, and avoids binding ls.

A backquote-style pattern has the form `qpat where qpat can have the following forms:

(qpat1 . qpat2)

Matches if expval is a cons cell whose car matches qpat1 and whose cdr matches qpat2. This readily generalizes to lists as in (qpat1 qpat2 …).

[qpat1 qpat2qpatm]

Matches if expval is a vector of length m whose 0..(m-1)th elements match qpat1, qpat2qpatm, respectively.

symbol
keyword
number
string

Matches if the corresponding element of expval is equal to the specified literal object.

,pattern

Matches if the corresponding element of expval matches pattern. Note that pattern is any kind that pcase supports. (In the example above, second-elem is a symbol core pattern; it therefore matches anything, and let-binds second-elem.)

The corresponding element is the portion of expval that is in the same structural position as the structural position of qpat in the backquote-style pattern. (In the example above, the corresponding element of second-elem is the second element of expval.)

Here is an example of using pcase to implement a simple interpreter for a little expression language (note that this requires lexical binding for the lambda expression in the fn clause to properly capture body and arg (see Lexical Binding):

(defun evaluate (form env)
  (pcase form
    (`(add ,x ,y)       (+ (evaluate x env)
                           (evaluate y env)))
    (`(call ,fun ,arg)  (funcall (evaluate fun env)
                                 (evaluate arg env)))
    (`(fn ,arg ,body)   (lambda (val)
                          (evaluate body (cons (cons arg val)
                                               env))))
    ((pred numberp)     form)
    ((pred symbolp)     (cdr (assq form env)))
    (_                  (error "Syntax error: %S" form))))

The first three clauses use backquote-style patterns. `(add ,x ,y) is a pattern that checks that form is a three-element list starting with the literal symbol add, then extracts the second and third elements and binds them to symbols x and y, respectively. The clause body evaluates x and y and adds the results. Similarly, the call clause implements a function call, and the fn clause implements an anonymous function definition.

The remaining clauses use core patterns. (pred numberp) matches if form is a number. On match, the body evaluates it. (pred symbolp) matches if form is a symbol. On match, the body looks up the symbol in env and returns its association. Finally, _ is the catch-all pattern that matches anything, so it’s suitable for reporting syntax errors.

Here are some sample programs in this small language, including their evaluation results:

(evaluate '(add 1 2) nil)                 ⇒ 3
(evaluate '(add x y) '((x . 1) (y . 2)))  ⇒ 3
(evaluate '(call (fn x (add 1 x)) 2) nil) ⇒ 3
(evaluate '(sub 1 2) nil)                 ⇒ error

Copyright © 1990-1996, 1998-2021 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote-Patterns.html