The pcase macro
For background, See Pattern-Matching Conditional.
Macro: pcase expression &rest clauses
Each clause in clauses has the form: (pattern body-forms…).
Evaluate expression to determine its value, expval. Find the first clause in clauses whose pattern matches expval and pass control to that clause’s body-forms.
If there is a match, the value of pcase is the value of the last of body-forms in the successful clause. Otherwise, pcase evaluates to nil.
Each pattern has to be a pcase pattern, which can use either one of the core patterns defined below, or one of the patterns defined via pcase-defmacro (see Extending pcase).
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:
_ (underscore)
Matches any expval. This is also known as don’t care or wildcard.
'val
Matches if expval equals val. The comparison is done as if by equal (see Equality Predicates).
keyword
integer
string
Matches if expval equals the literal object. This is a special case of 'val, above, possible because literal objects of these types are self-quoting.
symbol
Matches any expval, and additionally let-binds symbol to expval, such that this binding is available to body-forms (see Dynamic Binding).
If symbol is part of a sequencing pattern seqpat (e.g., by using and, below), the binding is also available to the portion of seqpat following the appearance of symbol. This usage has some caveats, see caveats.
Two symbols to avoid are t, which behaves like _ (above) and is deprecated, and nil, which signals an error. Likewise, it makes no sense to bind keyword symbols (see Variables that Never Change).
`qpat
A backquote-style pattern. See Backquote-Style Patterns, for the details.
(cl-type type)
Matches if expval is of type type, which is a type descriptor as accepted by cl-typep (see Type Predicates in Common Lisp Extensions). Examples:
(cl-type integer)
(cl-type (integer 0 10))(pred function)
Matches if the predicate function returns non-nil when called on expval. The test can be negated with the syntax (pred (not function)). The predicate function can have one of the following forms:
function name (a symbol)
Call the named function with one argument, expval.
Example: integerp
lambda expression
Call the anonymous function with one argument, expval (see Lambda Expressions).
Example: (lambda (n) (= 42 n))
function call with n args
Call the function (the first element of the function call) with n arguments (the other elements) and an additional n+1-th argument that is expval.
Example: (= 42)
In this example, the function is =, n is one, and the actual function call becomes: (= 42 expval).
function call with an _ arg
Call the function (the first element of the function call) with the specified arguments (the other elements) and replacing _ with expval.
Example: (gethash _ memo-table) In this example, the function is gethash, and the actual function call becomes: (gethash expval memo-table).
(app function pattern)
Matches if function called on expval returns a value that matches pattern. function can take one of the forms described for pred, above. Unlike pred, however, app tests the result against pattern, rather than against a boolean truth value.
(guard boolean-expression)
Matches if boolean-expression evaluates to non-nil.
(let pattern expr)
Evaluates expr to get exprval and matches if exprval matches pattern. (It is called let because pattern can bind symbols to values using symbol.)
A sequencing pattern (also known as seqpat) is a pattern that processes its sub-pattern arguments in sequence. There are two for pcase: and and or. They behave in a similar manner to the special forms that share their name (see Constructs for Combining Conditions), but instead of processing values, they process sub-patterns.
(and pattern1…)
Attempts to match pattern1…, in order, until one of them fails to match. In that case, and likewise fails to match, and the rest of the sub-patterns are not tested. If all sub-patterns match, and matches.
(or pattern1 pattern2…)
Attempts to match pattern1, pattern2, …, in order, until one of them succeeds. In that case, or likewise matches, and the rest of the sub-patterns are not tested.
To present a consistent environment (see Introduction to Evaluation) to body-forms (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 nil.
(rx rx-expr…)
Matches strings against the regexp rx-expr…, using the rx regexp notation (see The rx Structured Regexp Notation), as if by string-match.
In addition to the usual rx syntax, rx-expr… can contain the following constructs:
(let ref rx-expr…)
Bind the symbol ref to a submatch that matches rx-expr.... ref is bound in body-forms to the string of the submatch or nil, but can also be used in backref.
(backref ref)
Like the standard backref construct, but ref can here also be a name introduced by a previous (let ref …) construct.
Example: Advantage Over cl-case
Here’s an example that highlights some advantages pcase has over cl-case (see Conditionals in Common Lisp Extensions).
(pcase (get-return-code x)
;; string
((and (pred stringp) msg)
(message "%s" msg)) ;; symbol
('success (message "Done!"))
('would-block (message "Sorry, can't do it now"))
('read-only (message "The schmilblick is read-only"))
('access-denied (message "You do not have the needed rights")) ;; default
(code (message "Unknown return code %S" code)))With cl-case, you would need to explicitly declare a local variable code to hold the return value of get-return-code. Also cl-case is difficult to use with strings because it uses eql for comparison.
Example: Using and
A common idiom is to write a pattern starting with and, with one or more symbol 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.
(and
(pred integerp)
n ; bind n to expval
(guard (<= -9 n 9)))First, pred matches if (integerp expval) evaluates to non-nil. Next, n is a symbol pattern that matches anything and binds n to expval. Lastly, guard matches if the boolean expression (<= -9 n 9) (note the reference to n) evaluates to non-nil. If all these sub-patterns match, and matches.
Example: Reformulation with pcase
Here is another example that shows how to reformulate a simple matching task from its traditional implementation (function grok/traditional) to one using pcase (function grok/pcase). 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 Regular Expressions):
(defun grok/traditional (obj)
(if (and (stringp obj)
(string-match "^key:\\([[:digit:]]+\\)$" obj))
(match-string 1 obj)
(list "149" 'default)))(grok/traditional "key:0") ⇒ "0"
(grok/traditional "key:149") ⇒ "149"
(grok/traditional 'monolith) ⇒ ("149" default)The reformulation demonstrates symbol binding as well as or, and, pred, app and let.
(defun grok/pcase (obj)
(pcase obj
((or ; line 1
(and ; line 2
(pred stringp) ; line 3
(pred (string-match ; line 4
"^key:\\([[:digit:]]+\\)$")) ; line 5
(app (match-string 1) ; line 6
val)) ; line 7
(let val (list "149" 'default))) ; line 8
val))) ; line 9(grok/pcase "key:0") ⇒ "0"
(grok/pcase "key:149") ⇒ "149"
(grok/pcase 'monolith) ⇒ ("149" default)The bulk of grok/pcase is a single clause of a pcase form, the pattern on lines 1-8, the (single) body form on line 9. The pattern is or, which tries to match in turn its argument sub-patterns, first and (lines 2-7), then let (line 8), until one of them succeeds.
As in the previous example (see Example 1), and begins with a pred sub-pattern to ensure the following sub-patterns work with an object of the correct type (string, in this case). If (stringp expval) returns nil, pred fails, and thus and fails, too.
The next pred (lines 4-5) evaluates (string-match RX expval) and matches if the result is non-nil, which means that expval has the desired form: key:NUMBER. Again, failing this, pred fails and and, too.
Lastly (in this series of and sub-patterns), app evaluates (match-string 1 expval) (line 6) to get a temporary value tmp (i.e., the “NUMBER” substring) and tries to match tmp against pattern val (line 7). Since that is a symbol pattern, it matches unconditionally and additionally binds val to tmp.
Now that app has matched, all and sub-patterns have matched, and so and matches. Likewise, once and has matched, or matches and does not proceed to try sub-pattern let (line 8).
Let’s consider the situation where obj is not a string, or it is a string but has the wrong form. In this case, one of the pred (lines 3-5) fails to match, thus and (line 2) fails to match, thus or (line 1) proceeds to try sub-pattern let (line 8).
First, let evaluates (list "149" 'default) to get ("149" default), the exprval, and then tries to match exprval against pattern val. Since that is a symbol pattern, it matches unconditionally and additionally binds val to exprval. Now that let has matched, or matches.
Note how both and and let sub-patterns finish in the same way: by trying (always successfully) to match against the symbol pattern val, in the process binding val. Thus, or always matches and control always passes to the body form (line 9). Because that is the last body form in a successfully matched pcase clause, it is the value of pcase and likewise the return value of grok/pcase (see What Is a Function?).
Caveats for symbol in Sequencing Patterns
The preceding examples all use sequencing patterns which include the symbol sub-pattern in some way. Here are some important details about that usage.
When
symboloccurs more than once inseqpat, the second and subsequent occurrences do not expand to re-binding, but instead expand to an equality test usingeq.The following example features a
pcaseform with two clauses and twoseqpat, A and B. Both A and B first check thatexpvalis a pair (usingpred), and then bind symbols to thecarandcdrofexpval(using oneappeach).For A, because symbol
stis mentioned twice, the second mention becomes an equality test usingeq. On the other hand, B uses two separate symbols,s1ands2, both of which become independent bindings.emacs-lisp(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))emacs-lisp((and (pred consp) ; seqpat B (app car s1) ; first mention: s1 (app cdr s2)) ; first mention: s2 (list 'not-eq s1 s2))))emacs-lisp(let ((s "yow!")) (grok (cons s s))) ⇒ (eq "yow!") (grok (cons "yo!" "yo!")) ⇒ (not-eq "yo!" "yo!") (grok '(4 2)) ⇒ (not-eq 4 (2))Side-effecting code referencing
symbolis undefined. Avoid. For example, here are two similar functions. Both useand,symbolandguard:emacs-lisp(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)emacs-lisp(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) ; WRONG!The difference is in
boolean-expressioninguard:CLEANreferencesnsimply and directly, whileMAYBEreferencesnwith a side-effect, in the expression(incf n). Whenintegeris 3, here’s what happens:The first
nbinds it toexpval, i.e., the result of evaluating(* 3 3), or 9.boolean-expressionis evaluated:start: (< 9 (incf n) 100) becomes: (< 9 (setq n (1+ n)) 100) becomes: (< 9 (setq n (1+ 9)) 100)emacs-lispbecomes: (< 9 (setq n 10) 100) ; side-effect here! becomes: (< 9 n 100) ; n now bound to 10 becomes: (< 9 10 100) becomes: tBecause the result of the evaluation is non-
nil,guardmatches,andmatches, and control passes to that clause’s body forms.
Aside from the mathematical incorrectness of asserting that 9 is a double-digit integer, there is another problem with
MAYBE. The body form referencesnonce more, yet we do not see the updated value—10—at all. What happened to it?To sum up, it’s best to avoid side-effecting references to
symbolpatterns entirely, not only inboolean-expression(inguard), but also inexpr(inlet) andfunction(inpredandapp).On match, the clause’s body forms can reference the set of symbols the pattern let-binds. When
seqpatisand, this set is the union of all the symbols each of its sub-patterns let-binds. This makes sense because, forandto match, all the sub-patterns must match.When
seqpatisor, things are different:ormatches 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:emacs-lisp(require 'cl-lib) (pcase (read-number "Enter an integer: ") ((or (and (pred cl-evenp) e-num) ; bind e-num to expval o-num) ; bind o-num to expval (list e-num o-num)))emacs-lispEnter an integer: 42 error→ Symbol’s value as variable is void: o-numemacs-lispEnter an integer: 149 error→ Symbol’s value as variable is void: e-numEvaluating body form
(list e-num o-num)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:emacs-lisp(require 'cl-lib) (pcase (read-number "Enter an integer: ") ((and num ; line 1 (or (and (pred cl-evenp) ; line 2 (let spin 'even)) ; line 3 (let spin 'odd))) ; line 4 (list spin num))) ; line 5emacs-lispEnter an integer: 42 ⇒ (even 42)emacs-lispEnter an integer: 149 ⇒ (odd 149)Line 1 “factors out” the
expvalbinding withandandsymbol(in this case,num). On line 2,orbegins in the same way as before, but instead of binding different symbols, useslettwice (lines 3-4) to bind the same symbolspinin both sub-patterns. The value ofspindistinguishes the sub-patterns. The body form references both symbols (line 5).