summaryrefslogtreecommitdiff
path: root/devdocs/elisp/backquote-patterns.html
blob: f2d5166ed9ac7ad5c70ba228b6b176d86658dab6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 <h4 class="subsection">Backquote-Style Patterns</h4>    <p>This subsection describes <em>backquote-style patterns</em>, a set of builtin patterns that eases structural matching. For background, see <a href="pattern_002dmatching-conditional">Pattern-Matching Conditional</a>. </p> <p>Backquote-style patterns are a powerful set of <code>pcase</code> pattern extensions (created using <code>pcase-defmacro</code>) that make it easy to match <var>expval</var> against specifications of its <em>structure</em>. </p> <p>For example, to match <var>expval</var> 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: </p> <div class="example"> <pre class="example">(and (pred listp)
     ls
</pre>
<pre class="example">     (guard (= 2 (length ls)))
     (guard (string= "first" (car ls)))
     (let second-elem (cadr ls)))
</pre>
</div> <p>or you can write the equivalent backquote-style pattern: </p> <div class="example"> <pre class="example">`("first" ,second-elem)
</pre>
</div> <p>The backquote-style pattern is more concise, resembles the structure of <var>expval</var>, and avoids binding <code>ls</code>. </p> <p>A backquote-style pattern has the form <code>`<var>qpat</var></code> where <var>qpat</var> can have the following forms: </p> <dl compact> <dt><code>(<var>qpat1</var> . <var>qpat2</var>)</code></dt> <dd>
<p>Matches if <var>expval</var> is a cons cell whose <code>car</code> matches <var>qpat1</var> and whose <code>cdr</code> matches <var>qpat2</var>. This readily generalizes to lists as in <code>(<var>qpat1</var> <var>qpat2</var> …)</code>. </p> </dd> <dt><code>[<var>qpat1</var> <var>qpat2</var> … <var>qpatm</var>]</code></dt> <dd>
<p>Matches if <var>expval</var> is a vector of length <var>m</var> whose <code>0</code>..<code>(<var>m</var>-1)</code>th elements match <var>qpat1</var>, <var>qpat2</var> … <var>qpatm</var>, respectively. </p> </dd> <dt><code><var>symbol</var></code></dt> <dt><code><var>keyword</var></code></dt> <dt><code><var>number</var></code></dt> <dt><code><var>string</var></code></dt> <dd>
<p>Matches if the corresponding element of <var>expval</var> is <code>equal</code> to the specified literal object. </p> </dd> <dt><code>,<var>pattern</var></code></dt> <dd><p>Matches if the corresponding element of <var>expval</var> matches <var>pattern</var>. Note that <var>pattern</var> is any kind that <code>pcase</code> supports. (In the example above, <code>second-elem</code> is a <var>symbol</var> core pattern; it therefore matches anything, and let-binds <code>second-elem</code>.) </p></dd> </dl> <p>The <em>corresponding element</em> is the portion of <var>expval</var> that is in the same structural position as the structural position of <var>qpat</var> in the backquote-style pattern. (In the example above, the corresponding element of <code>second-elem</code> is the second element of <var>expval</var>.) </p> <p>Here is an example of using <code>pcase</code> to implement a simple interpreter for a little expression language (note that this requires lexical binding for the lambda expression in the <code>fn</code> clause to properly capture <code>body</code> and <code>arg</code> (see <a href="lexical-binding">Lexical Binding</a>): </p> <div class="example"> <pre class="example">(defun evaluate (form env)
  (pcase form
    (`(add ,x ,y)       (+ (evaluate x env)
                           (evaluate y env)))
</pre>
<pre class="example">    (`(call ,fun ,arg)  (funcall (evaluate fun env)
                                 (evaluate arg env)))
    (`(fn ,arg ,body)   (lambda (val)
                          (evaluate body (cons (cons arg val)
                                               env))))
</pre>
<pre class="example">    ((pred numberp)     form)
    ((pred symbolp)     (cdr (assq form env)))
    (_                  (error "Syntax error: %S" form))))
</pre>
</div> <p>The first three clauses use backquote-style patterns. <code>`(add ,x ,y)</code> is a pattern that checks that <code>form</code> is a three-element list starting with the literal symbol <code>add</code>, then extracts the second and third elements and binds them to symbols <code>x</code> and <code>y</code>, respectively. The clause body evaluates <code>x</code> and <code>y</code> and adds the results. Similarly, the <code>call</code> clause implements a function call, and the <code>fn</code> clause implements an anonymous function definition. </p> <p>The remaining clauses use core patterns. <code>(pred numberp)</code> matches if <code>form</code> is a number. On match, the body evaluates it. <code>(pred symbolp)</code> matches if <code>form</code> is a symbol. On match, the body looks up the symbol in <code>env</code> and returns its association. Finally, <code>_</code> is the catch-all pattern that matches anything, so it’s suitable for reporting syntax errors. </p> <p>Here are some sample programs in this small language, including their evaluation results: </p> <div class="example"> <pre class="example">(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
</pre>
</div><div class="_attribution">
  <p class="_attribution-p">
    Copyright &copy; 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
    <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote-Patterns.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote-Patterns.html</a>
  </p>
</div>