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 qpat2 … qpatm]
Matches if expval is a vector of length m whose
0
..(m-1)
th elements match qpat1,
qpat2 … qpatm, 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. This is known as
destructuring, see Destructuring with pcase
Patterns.
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