diff options
Diffstat (limited to 'devdocs/elisp/pcase-macro.html')
| -rw-r--r-- | devdocs/elisp/pcase-macro.html | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/devdocs/elisp/pcase-macro.html b/devdocs/elisp/pcase-macro.html new file mode 100644 index 00000000..431c65cb --- /dev/null +++ b/devdocs/elisp/pcase-macro.html @@ -0,0 +1,161 @@ + <h4 class="subsection">The pcase macro</h4> <p>For background, See <a href="pattern_002dmatching-conditional">Pattern-Matching Conditional</a>. </p> <dl> <dt id="pcase">Macro: <strong>pcase</strong> <em>expression &rest clauses</em> +</dt> <dd> +<p>Each clause in <var>clauses</var> has the form: <code>(<var>pattern</var> <var><span class="nolinebreak">body-forms</span></var>…)</code>. </p> <p>Evaluate <var>expression</var> to determine its value, <var>expval</var>. Find the first clause in <var>clauses</var> whose <var>pattern</var> matches <var>expval</var> and pass control to that clause’s <var>body-forms</var>. </p> <p>If there is a match, the value of <code>pcase</code> is the value of the last of <var>body-forms</var> in the successful clause. Otherwise, <code>pcase</code> evaluates to <code>nil</code>. </p> +</dd> +</dl> <p>Each <var>pattern</var> has to be a <em>pcase pattern</em>, which can use either one of the core patterns defined below, or one of the patterns defined via <code>pcase-defmacro</code> (see <a href="extending-pcase">Extending pcase</a>). </p> <p>The rest of this subsection describes different forms of core patterns, presents some examples, and concludes with important caveats on using the let-binding facility provided by some pattern forms. A core pattern can have the following forms: </p> <dl compact> <dt><code>_<span class="roman"> (underscore)</span></code></dt> <dd> +<p>Matches any <var>expval</var>. This is also known as <em>don’t care</em> or <em>wildcard</em>. </p> </dd> <dt><code>'<var>val</var></code></dt> <dd> +<p>Matches if <var>expval</var> equals <var>val</var>. The comparison is done as if by <code>equal</code> (see <a href="equality-predicates">Equality Predicates</a>). </p> </dd> <dt><code><var>keyword</var></code></dt> <dt><code><var>integer</var></code></dt> <dt><code><var>string</var></code></dt> <dd> +<p>Matches if <var>expval</var> equals the literal object. This is a special case of <code>'<var>val</var></code>, above, possible because literal objects of these types are self-quoting. </p> </dd> <dt><code><var>symbol</var></code></dt> <dd> +<p>Matches any <var>expval</var>, and additionally let-binds <var>symbol</var> to <var>expval</var>, such that this binding is available to <var>body-forms</var> (see <a href="dynamic-binding">Dynamic Binding</a>). </p> <p>If <var>symbol</var> is part of a sequencing pattern <var>seqpat</var> (e.g., by using <code>and</code>, below), the binding is also available to the portion of <var>seqpat</var> following the appearance of <var>symbol</var>. This usage has some caveats, see <a href="#pcase_002dsymbol_002dcaveats">caveats</a>. </p> <p>Two symbols to avoid are <code>t</code>, which behaves like <code>_</code> (above) and is deprecated, and <code>nil</code>, which signals an error. Likewise, it makes no sense to bind keyword symbols (see <a href="constant-variables">Constant Variables</a>). </p> </dd> <dt><code>(cl-type <var>type</var>)</code></dt> <dd> +<p>Matches if <var>expval</var> is of type <var>type</var>, which is a type descriptor as accepted by <code>cl-typep</code> (see <a href="https://www.gnu.org/software/emacs/manual/html_node/cl/Type-Predicates.html#Type-Predicates">Type Predicates</a> in <cite>Common Lisp Extensions</cite>). Examples: </p> <div class="lisp"> <pre class="lisp">(cl-type integer) +(cl-type (integer 0 10)) +</pre> +</div> </dd> <dt><code>(pred <var>function</var>)</code></dt> <dd> +<p>Matches if the predicate <var>function</var> returns non-<code>nil</code> when called on <var>expval</var>. The test can be negated with the syntax <code>(pred (not <var>function</var>))</code>. The predicate <var>function</var> can have one of the following forms: </p> <dl compact> <dt>function name (a symbol)</dt> <dd> +<p>Call the named function with one argument, <var>expval</var>. </p> <p>Example: <code>integerp</code> </p> </dd> <dt>lambda expression</dt> <dd> +<p>Call the anonymous function with one argument, <var>expval</var> (see <a href="lambda-expressions">Lambda Expressions</a>). </p> <p>Example: <code>(lambda (n) (= 42 n))</code> </p> </dd> <dt>function call with <var>n</var> args</dt> <dd> +<p>Call the function (the first element of the function call) with <var>n</var> arguments (the other elements) and an additional <var>n</var>+1-th argument that is <var>expval</var>. </p> <p>Example: <code>(= 42)</code> In this example, the function is <code>=</code>, <var>n</var> is one, and the actual function call becomes: <code>(= 42 <var>expval</var>)</code>. </p> +</dd> </dl> </dd> <dt><code>(app <var>function</var> <var>pattern</var>)</code></dt> <dd> +<p>Matches if <var>function</var> called on <var>expval</var> returns a value that matches <var>pattern</var>. <var>function</var> can take one of the forms described for <code>pred</code>, above. Unlike <code>pred</code>, however, <code>app</code> tests the result against <var>pattern</var>, rather than against a boolean truth value. </p> </dd> <dt><code>(guard <var>boolean-expression</var>)</code></dt> <dd> +<p>Matches if <var>boolean-expression</var> evaluates to non-<code>nil</code>. </p> </dd> <dt><code>(let <var>pattern</var> <var>expr</var>)</code></dt> <dd><p>Evaluates <var>expr</var> to get <var>exprval</var> and matches if <var>exprval</var> matches <var>pattern</var>. (It is called <code>let</code> because <var>pattern</var> can bind symbols to values using <var>symbol</var>.) </p></dd> </dl> <p>A <em>sequencing pattern</em> (also known as <var>seqpat</var>) is a pattern that processes its sub-pattern arguments in sequence. There are two for <code>pcase</code>: <code>and</code> and <code>or</code>. They behave in a similar manner to the special forms that share their name (see <a href="combining-conditions">Combining Conditions</a>), but instead of processing values, they process sub-patterns. </p> <dl compact> <dt><code>(and <var>pattern1</var>…)</code></dt> <dd> +<p>Attempts to match <var>pattern1</var>…, in order, until one of them fails to match. In that case, <code>and</code> likewise fails to match, and the rest of the sub-patterns are not tested. If all sub-patterns match, <code>and</code> matches. </p> </dd> <dt><code>(or <var>pattern1</var> <var>pattern2</var>…)</code></dt> <dd> +<p>Attempts to match <var>pattern1</var>, <var>pattern2</var>, …, in order, until one of them succeeds. In that case, <code>or</code> likewise matches, and the rest of the sub-patterns are not tested. </p> <p>To present a consistent environment (see <a href="intro-eval">Intro Eval</a>) to <var>body-forms</var> (thus avoiding an evaluation error on match), the set of variables bound by the pattern is the union of the variables bound by each sub-pattern. If a variable is not bound by the sub-pattern that matched, then it is bound to <code>nil</code>. </p> +</dd> <dt><code>(rx <var>rx-expr</var>…)</code></dt> <dd> +<p>Matches strings against the regexp <var>rx-expr</var>…, using the <code>rx</code> regexp notation (see <a href="rx-notation">Rx Notation</a>), as if by <code>string-match</code>. </p> <p>In addition to the usual <code>rx</code> syntax, <var>rx-expr</var>… can contain the following constructs: </p> <dl compact> <dt><code>(let <var>ref</var> <var>rx-expr</var>…)</code></dt> <dd> +<p>Bind the symbol <var>ref</var> to a submatch that matches <var>rx-expr</var><small class="enddots">...</small>. <var>ref</var> is bound in <var>body-forms</var> to the string of the submatch or nil, but can also be used in <code>backref</code>. </p> </dd> <dt><code>(backref <var>ref</var>)</code></dt> <dd><p>Like the standard <code>backref</code> construct, but <var>ref</var> can here also be a name introduced by a previous <code>(let <var>ref</var> …)</code> construct. </p></dd> </dl> </dd> </dl> <h4 class="subheading">Example: Advantage Over <code>cl-case</code> +</h4> <p>Here’s an example that highlights some advantages <code>pcase</code> has over <code>cl-case</code> (see <a href="https://www.gnu.org/software/emacs/manual/html_node/cl/Conditionals.html#Conditionals">Conditionals</a> in <cite>Common Lisp Extensions</cite>). </p> <div class="example"> <pre class="example">(pcase (get-return-code x) + ;; string + ((and (pred stringp) msg) + (message "%s" msg)) +</pre> +<pre class="example"> ;; symbol + ('success (message "Done!")) + ('would-block (message "Sorry, can't do it now")) + ('read-only (message "The shmliblick is read-only")) + ('access-denied (message "You do not have the needed rights")) +</pre> +<pre class="example"> ;; default + (code (message "Unknown return code %S" code))) +</pre> +</div> <p>With <code>cl-case</code>, you would need to explicitly declare a local variable <code>code</code> to hold the return value of <code>get-return-code</code>. Also <code>cl-case</code> is difficult to use with strings because it uses <code>eql</code> for comparison. </p> <h4 class="subheading">Example: Using <code>and</code> +</h4> <p>A common idiom is to write a pattern starting with <code>and</code>, with one or more <var>symbol</var> sub-patterns providing bindings to the sub-patterns that follow (as well as to the body forms). For example, the following pattern matches single-digit integers. </p> <div class="example"> <pre class="example">(and + (pred integerp) + n ; <span class="roman">bind <code>n</code> to <var>expval</var></span> + (guard (<= -9 n 9))) +</pre> +</div> <p>First, <code>pred</code> matches if <code>(integerp <var>expval</var>)</code> evaluates to non-<code>nil</code>. Next, <code>n</code> is a <var>symbol</var> pattern that matches anything and binds <code>n</code> to <var>expval</var>. Lastly, <code>guard</code> matches if the boolean expression <code>(<= <span class="nolinebreak">-9</span> n 9)</code> (note the reference to <code>n</code>) evaluates to non-<code>nil</code>. If all these sub-patterns match, <code>and</code> matches. </p> <h4 class="subheading">Example: Reformulation with <code>pcase</code> +</h4> <p>Here is another example that shows how to reformulate a simple matching task from its traditional implementation (function <code>grok/traditional</code>) to one using <code>pcase</code> (function <code>grok/pcase</code>). The docstring for both these functions is: “If OBJ is a string of the form "key:NUMBER", return NUMBER (a string). Otherwise, return the list ("149" default).” First, the traditional implementation (see <a href="regular-expressions">Regular Expressions</a>): </p> <div class="example"> <pre class="example">(defun grok/traditional (obj) + (if (and (stringp obj) + (string-match "^key:\\([[:digit:]]+\\)$" obj)) + (match-string 1 obj) + (list "149" 'default))) +</pre> + +<pre class="example">(grok/traditional "key:0") ⇒ "0" +(grok/traditional "key:149") ⇒ "149" +(grok/traditional 'monolith) ⇒ ("149" default) +</pre> +</div> <p>The reformulation demonstrates <var>symbol</var> binding as well as <code>or</code>, <code>and</code>, <code>pred</code>, <code>app</code> and <code>let</code>. </p> <div class="example"> <pre class="example">(defun grok/pcase (obj) + (pcase obj + ((or ; <span class="roman">line 1</span> + (and ; <span class="roman">line 2</span> + (pred stringp) ; <span class="roman">line 3</span> + (pred (string-match ; <span class="roman">line 4</span> + "^key:\\([[:digit:]]+\\)$")) ; <span class="roman">line 5</span> + (app (match-string 1) ; <span class="roman">line 6</span> + val)) ; <span class="roman">line 7</span> + (let val (list "149" 'default))) ; <span class="roman">line 8</span> + val))) ; <span class="roman">line 9</span> +</pre> + +<pre class="example">(grok/pcase "key:0") ⇒ "0" +(grok/pcase "key:149") ⇒ "149" +(grok/pcase 'monolith) ⇒ ("149" default) +</pre> +</div> <p>The bulk of <code>grok/pcase</code> is a single clause of a <code>pcase</code> form, the pattern on lines 1-8, the (single) body form on line 9. The pattern is <code>or</code>, which tries to match in turn its argument sub-patterns, first <code>and</code> (lines 2-7), then <code>let</code> (line 8), until one of them succeeds. </p> <p>As in the previous example (see <a href="#pcase_002dexample_002d1">Example 1</a>), <code>and</code> begins with a <code>pred</code> sub-pattern to ensure the following sub-patterns work with an object of the correct type (string, in this case). If <code>(stringp <var>expval</var>)</code> returns <code>nil</code>, <code>pred</code> fails, and thus <code>and</code> fails, too. </p> <p>The next <code>pred</code> (lines 4-5) evaluates <code><span class="nolinebreak">(string-match</span> RX <var>expval</var>)</code> and matches if the result is non-<code>nil</code>, which means that <var>expval</var> has the desired form: <code>key:NUMBER</code>. Again, failing this, <code>pred</code> fails and <code>and</code>, too. </p> <p>Lastly (in this series of <code>and</code> sub-patterns), <code>app</code> evaluates <code><span class="nolinebreak">(match-string</span> 1 <var>expval</var>)</code> (line 6) to get a temporary value <var>tmp</var> (i.e., the “NUMBER” substring) and tries to match <var>tmp</var> against pattern <code>val</code> (line 7). Since that is a <var>symbol</var> pattern, it matches unconditionally and additionally binds <code>val</code> to <var>tmp</var>. </p> <p>Now that <code>app</code> has matched, all <code>and</code> sub-patterns have matched, and so <code>and</code> matches. Likewise, once <code>and</code> has matched, <code>or</code> matches and does not proceed to try sub-pattern <code>let</code> (line 8). </p> <p>Let’s consider the situation where <code>obj</code> is not a string, or it is a string but has the wrong form. In this case, one of the <code>pred</code> (lines 3-5) fails to match, thus <code>and</code> (line 2) fails to match, thus <code>or</code> (line 1) proceeds to try sub-pattern <code>let</code> (line 8). </p> <p>First, <code>let</code> evaluates <code>(list "149" 'default)</code> to get <code>("149" default)</code>, the <var>exprval</var>, and then tries to match <var>exprval</var> against pattern <code>val</code>. Since that is a <var>symbol</var> pattern, it matches unconditionally and additionally binds <code>val</code> to <var>exprval</var>. Now that <code>let</code> has matched, <code>or</code> matches. </p> <p>Note how both <code>and</code> and <code>let</code> sub-patterns finish in the same way: by trying (always successfully) to match against the <var>symbol</var> pattern <code>val</code>, in the process binding <code>val</code>. Thus, <code>or</code> always matches and control always passes to the body form (line 9). Because that is the last body form in a successfully matched <code>pcase</code> clause, it is the value of <code>pcase</code> and likewise the return value of <code>grok/pcase</code> (see <a href="what-is-a-function">What Is a Function</a>). </p> <h4 class="subheading">Caveats for <var>symbol</var> in Sequencing Patterns</h4> <p>The preceding examples all use sequencing patterns which include the <var>symbol</var> sub-pattern in some way. Here are some important details about that usage. </p> <ol> <li> When <var>symbol</var> occurs more than once in <var>seqpat</var>, the second and subsequent occurrences do not expand to re-binding, but instead expand to an equality test using <code>eq</code>. <p>The following example features a <code>pcase</code> form with two clauses and two <var>seqpat</var>, A and B. Both A and B first check that <var>expval</var> is a pair (using <code>pred</code>), and then bind symbols to the <code>car</code> and <code>cdr</code> of <var>expval</var> (using one <code>app</code> each). </p> <p>For A, because symbol <code>st</code> is mentioned twice, the second mention becomes an equality test using <code>eq</code>. On the other hand, B uses two separate symbols, <code>s1</code> and <code>s2</code>, both of which become independent bindings. </p> <div class="example"> <pre class="example">(defun grok (object) + (pcase object + ((and (pred consp) ; seqpat A + (app car st) ; first mention: st + (app cdr st)) ; second mention: st + (list 'eq st)) +</pre> +<pre class="example"> ((and (pred consp) ; seqpat B + (app car s1) ; first mention: s1 + (app cdr s2)) ; first mention: s2 + (list 'not-eq s1 s2)))) +</pre> + +<pre class="example">(let ((s "yow!")) + (grok (cons s s))) ⇒ (eq "yow!") +(grok (cons "yo!" "yo!")) ⇒ (not-eq "yo!" "yo!") +(grok '(4 2)) ⇒ (not-eq 4 (2)) +</pre> +</div> </li> +<li> Side-effecting code referencing <var>symbol</var> is undefined. Avoid. For example, here are two similar functions. Both use <code>and</code>, <var>symbol</var> and <code>guard</code>: <div class="example"> <pre class="example">(defun square-double-digit-p/CLEAN (integer) + (pcase (* integer integer) + ((and n (guard (< 9 n 100))) (list 'yes n)) + (sorry (list 'no sorry)))) + +(square-double-digit-p/CLEAN 9) ⇒ (yes 81) +(square-double-digit-p/CLEAN 3) ⇒ (no 9) +</pre> + +<pre class="example">(defun square-double-digit-p/MAYBE (integer) + (pcase (* integer integer) + ((and n (guard (< 9 (incf n) 100))) (list 'yes n)) + (sorry (list 'no sorry)))) + +(square-double-digit-p/MAYBE 9) ⇒ (yes 81) +(square-double-digit-p/MAYBE 3) ⇒ (yes 9) ; <span class="roman">WRONG!</span> +</pre> +</div> <p>The difference is in <var>boolean-expression</var> in <code>guard</code>: <code>CLEAN</code> references <code>n</code> simply and directly, while <code>MAYBE</code> references <code>n</code> with a side-effect, in the expression <code>(incf n)</code>. When <code>integer</code> is 3, here’s what happens: </p> <ul> <li> The first <code>n</code> binds it to <var>expval</var>, i.e., the result of evaluating <code>(* 3 3)</code>, or 9. </li> +<li> <var>boolean-expression</var> is evaluated: <div class="example"> <pre class="example">start: (< 9 (incf n) 100) +becomes: (< 9 (setq n (1+ n)) 100) +becomes: (< 9 (setq n (1+ 9)) 100) +</pre> +<pre class="example">becomes: (< 9 (setq n 10) 100) + ; <span class="roman">side-effect here!</span> +becomes: (< 9 n 100) ; <span class="roman"><code>n</code> now bound to 10</span> +becomes: (< 9 10 100) +becomes: t +</pre> +</div> </li> +<li> Because the result of the evaluation is non-<code>nil</code>, <code>guard</code> matches, <code>and</code> matches, and control passes to that clause’s body forms. </li> +</ul> <p>Aside from the mathematical incorrectness of asserting that 9 is a double-digit integer, there is another problem with <code>MAYBE</code>. The body form references <code>n</code> once more, yet we do not see the updated value—10—at all. What happened to it? </p> <p>To sum up, it’s best to avoid side-effecting references to <var>symbol</var> patterns entirely, not only in <var>boolean-expression</var> (in <code>guard</code>), but also in <var>expr</var> (in <code>let</code>) and <var>function</var> (in <code>pred</code> and <code>app</code>). </p> </li> +<li> On match, the clause’s body forms can reference the set of symbols the pattern let-binds. When <var>seqpat</var> is <code>and</code>, this set is the union of all the symbols each of its sub-patterns let-binds. This makes sense because, for <code>and</code> to match, all the sub-patterns must match. <p>When <var>seqpat</var> is <code>or</code>, things are different: <code>or</code> matches at the first sub-pattern that matches; the rest of the sub-patterns are ignored. It makes no sense for each sub-pattern to let-bind a different set of symbols because the body forms have no way to distinguish which sub-pattern matched and choose among the different sets. For example, the following is invalid: </p> <div class="example"> <pre class="example">(require 'cl-lib) +(pcase (read-number "Enter an integer: ") + ((or (and (pred cl-evenp) + e-num) ; <span class="roman">bind <code>e-num</code> to <var>expval</var></span> + o-num) ; <span class="roman">bind <code>o-num</code> to <var>expval</var></span> + (list e-num o-num))) +</pre> + +<pre class="example">Enter an integer: 42 +error→ Symbol’s value as variable is void: o-num +</pre> +<pre class="example">Enter an integer: 149 +error→ Symbol’s value as variable is void: e-num +</pre> +</div> <p>Evaluating body form <code>(list <span class="nolinebreak">e-num</span> <span class="nolinebreak">o-num)</span></code> signals error. To distinguish between sub-patterns, you can use another symbol, identical in name in all sub-patterns but differing in value. Reworking the above example: </p> <div class="example"> <pre class="example">(require 'cl-lib) +(pcase (read-number "Enter an integer: ") + ((and num ; <span class="roman">line 1</span> + (or (and (pred cl-evenp) ; <span class="roman">line 2</span> + (let spin 'even)) ; <span class="roman">line 3</span> + (let spin 'odd))) ; <span class="roman">line 4</span> + (list spin num))) ; <span class="roman">line 5</span> +</pre> + +<pre class="example">Enter an integer: 42 +⇒ (even 42) +</pre> +<pre class="example">Enter an integer: 149 +⇒ (odd 149) +</pre> +</div> <p>Line 1 “factors out” the <var>expval</var> binding with <code>and</code> and <var>symbol</var> (in this case, <code>num</code>). On line 2, <code>or</code> begins in the same way as before, but instead of binding different symbols, uses <code>let</code> twice (lines 3-4) to bind the same symbol <code>spin</code> in both sub-patterns. The value of <code>spin</code> distinguishes the sub-patterns. The body form references both symbols (line 5). </p> +</li> +</ol><div class="_attribution"> + <p class="_attribution-p"> + Copyright © 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/pcase-Macro.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/pcase-Macro.html</a> + </p> +</div> |
