[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] fix/bug-31311-pcase-doc-squash 2df20b3 4/4: Overhaul pcase
From: |
Thien-Thi Nguyen |
Subject: |
[Emacs-diffs] fix/bug-31311-pcase-doc-squash 2df20b3 4/4: Overhaul pcase documentation |
Date: |
Mon, 21 May 2018 12:36:14 -0400 (EDT) |
branch: fix/bug-31311-pcase-doc-squash
commit 2df20b3a1624a847429d2a6669d949214fffe3fa
Author: Thien-Thi Nguyen <address@hidden>
Commit: Thien-Thi Nguyen <address@hidden>
Overhaul pcase documentation
Suggested by Drew Adams (Bug#31311).
* doc/lispref/control.texi (Control Structures):
Add "Pattern-Matching Conditional" to menu, before "Iteration".
(Conditionals): Delete menu.
(Pattern matching case statement): Delete node/subsection,
by actually moving, renaming, and overhauling it to...
(Pattern-Matching Conditional): ...new node/section.
(pcase Macro): New node/subsection.
(Extending pcase): Likewise.
(Backquote Patterns): Likewise.
* doc/lispref/elisp.texi (Top) (detailmenu)
[Control Structures]: Add "Pattern-Matching Conditional".
[Conditionals]: Delete section.
* lisp/emacs-lisp/pcase.el (pcase): Rewrite docstring.
(pcase-defmacro \` (qpat) ...): Likewise.
---
doc/lispref/control.texi | 960 +++++++++++++++++++++++++++++++++++++----------
doc/lispref/elisp.texi | 5 +-
lisp/emacs-lisp/pcase.el | 102 ++---
3 files changed, 804 insertions(+), 263 deletions(-)
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index adec632..33051a6 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -38,6 +38,7 @@ structure constructs (@pxref{Macros}).
* Sequencing:: Evaluation in textual order.
* Conditionals:: @code{if}, @code{cond}, @code{when}, @code{unless}.
* Combining Conditions:: @code{and}, @code{or}, @code{not}.
+* Pattern-Matching Conditional:: How to use @code{pcase} and friends.
* Iteration:: @code{while} loops.
* Generators:: Generic sequences and coroutines.
* Nonlocal Exits:: Jumping out of a sequence.
@@ -288,214 +289,6 @@ For example:
@end group
@end example
address@hidden
-* Pattern matching case statement::
address@hidden menu
-
address@hidden Pattern matching case statement
address@hidden Pattern matching case statement
address@hidden pcase
address@hidden pattern matching
-
-The @code{cond} form lets you choose between alternatives using
-predicate conditions that compare values of expressions against
-specific values known and written in advance. However, sometimes it
-is useful to select alternatives based on more general conditions that
-distinguish between broad classes of values. The @code{pcase} macro
-allows you to choose between alternatives based on matching the value
-of an expression against a series of patterns. A pattern can be a
-literal value (for comparisons to literal values you'd use
address@hidden), or it can be a more general description of the expected
-structure of the expression's value.
-
address@hidden pcase expression &rest clauses
-Evaluate @var{expression} and choose among an arbitrary number of
-alternatives based on the value of @var{expression}. The possible
-alternatives are specified by @var{clauses}, each of which must be a
-list of the form @code{(@var{pattern} @address@hidden)}.
address@hidden tries to match the value of @var{expression} to the
address@hidden of each clause, in textual order. If the value matches,
-the clause succeeds; @code{pcase} then evaluates its @var{body-forms},
-and returns the value of the last of @var{body-forms}. Any remaining
address@hidden are ignored. If no clauses match, then the @code{pcase}
-form evaluates to @code{nil}.
-
-The @var{pattern} part of a clause can be of one of two types:
address@hidden, a pattern quoted with a backquote; or a
address@hidden, which is not quoted. UPatterns are simpler, so we
-describe them first.
-
-Note: In the description of the patterns below, we use ``the value
-being matched'' to refer to the value of the @var{expression} that is
-the first argument of @code{pcase}.
-
-A UPattern can have the following forms:
-
address@hidden @code
-
address@hidden '@var{val}
-Matches if the value being matched is @code{equal} to @var{val}.
address@hidden @var{atom}
-Matches any @var{atom}, which can be a keyword, a number, or a string.
-(These are self-quoting, so this kind of UPattern is actually a
-shorthand for @code{'@var{atom}}.) Note that a string or a float
-matches any string or float with the same contents/value.
address@hidden _
-Matches any value. This is known as @dfn{don't care} or @dfn{wildcard}.
address@hidden @var{symbol}
-Matches any value, and additionally let-binds @var{symbol} to the
-value it matched, so that you can later refer to it, either in the
address@hidden or also later in the pattern.
address@hidden (pred @var{predfun})
-Matches if the predicate function @var{predfun} returns address@hidden
-when called with the value being matched as its argument.
address@hidden can be one of the possible forms described below.
address@hidden (guard @var{boolean-expression})
-Matches if @var{boolean-expression} evaluates to address@hidden This
-allows you to include in a UPattern boolean conditions that refer to
-symbols bound to values (including the value being matched) by
-previous UPatterns. Typically used inside an @code{and} UPattern, see
-below. For example, @address@hidden(and x (guard (< x 10)))}} is a pattern
-which matches any number smaller than 10 and let-binds the variable
address@hidden to that number.
address@hidden (let @var{upattern} @var{expression})
-Matches if the specified @var{expression} matches the specified
address@hidden This allows matching a pattern against the value of
-an @emph{arbitrary} expression, not just the expression that is the
-first argument to @code{pcase}. (It is called @code{let} because
address@hidden can bind symbols to values using the @var{symbol}
-UPattern. For example:
address@hidden@code{((or `(key . ,val) (let val 5)) val)}}.)
address@hidden (app @var{function} @var{upattern})
-Matches if @var{function} applied to the value being matched returns a
-value that matches @var{upattern}. This is like the @code{pred}
-UPattern, except that it tests the result against @var{upattern},
-rather than against a boolean truth value. The @var{function} call can
-use one of the forms described below.
address@hidden (or @var{upattern1} @address@hidden)
-Matches if one the argument UPatterns matches. As soon as the first
-matching UPattern is found, the rest are not tested. For this reason,
-if any of the UPatterns let-bind symbols to the matched value, they
-should all bind the same symbols.
address@hidden (and @var{upattern1} @address@hidden)
-Matches if all the argument UPatterns match.
address@hidden table
-
-The function calls used in the @code{pred} and @code{app} UPatterns
-can have one of the following forms:
-
address@hidden @asis
address@hidden function symbol, like @code{integerp}
-In this case, the named function is applied to the value being
-matched.
address@hidden lambda-function @code{(lambda (@var{arg}) @var{body})}
-In this case, the lambda-function is called with one argument, the
-value being matched.
address@hidden @code{(@var{func} @address@hidden)}
-This is a function call with @var{n} specified arguments; the function
-is called with these @var{n} arguments and an additional @var{n}+1-th
-argument that is the value being matched.
address@hidden table
-
-Here's an illustrative example of using UPatterns:
-
address@hidden FIXME: This example should use every one of the UPatterns
described
address@hidden above at least once.
address@hidden
-(pcase (get-return-code x)
- ('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"))
- (code (message "Unknown return code %S" code)))
address@hidden example
-
-In addition, you can use backquoted patterns that are more powerful.
-They allow matching the value of the @var{expression} that is the
-first argument of @code{pcase} against specifications of its
address@hidden For example, you can specify that the value must be
-a list of 2 elements whose first element is a specific string and the
-second element is any value with a backquoted pattern like
address@hidden("first" ,second-elem)}.
-
-Backquoted patterns have the form @address@hidden where
address@hidden can have the following forms:
-
address@hidden @code
address@hidden (@var{qpattern1} . @var{qpattern2})
-Matches if the value being matched is a cons cell whose @code{car}
-matches @var{qpattern1} and whose @code{cdr} matches @var{qpattern2}.
-This readily generalizes to backquoted lists as in
address@hidden@code{(@var{qpattern1} @var{qpattern2} @dots{})}}.
address@hidden address@hidden @var{qpattern2} @dots{} @var{qpatternm}]
-Matches if the value being matched is a vector of length @var{m} whose
address@hidden@code{(@var{m}-1)}th elements match @var{qpattern1},
address@hidden @dots{} @var{qpatternm}, respectively.
address@hidden @var{atom}
-Matches if corresponding element of the value being matched is
address@hidden to the specified @var{atom}.
address@hidden ,@var{upattern}
-Matches if the corresponding element of the value being matched
-matches the specified @var{upattern}.
address@hidden table
-
-Note that uses of QPatterns can be expressed using only UPatterns, as
-QPatterns are implemented on top of UPatterns using
address@hidden, described below. However, using QPatterns will
-in many cases lead to a more readable code.
address@hidden FIXME: There should be an example here showing how a 'pcase' that
address@hidden uses QPatterns can be rewritten using UPatterns.
-
address@hidden defmac
-
-Here is an example of using @code{pcase} to implement a simple
-interpreter for a little expression language (note that this example
-requires lexical binding, @pxref{Lexical Binding}):
-
address@hidden
-(defun evaluate (exp env)
- (pcase exp
- (`(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) exp)
- ((pred symbolp) (cdr (assq exp env)))
- (_ (error "Unknown expression %S" exp))))
address@hidden example
-
-Here @code{`(add ,x ,y)} is a pattern that checks that @code{exp} is a
-three-element list starting with the literal symbol @code{add}, then
-extracts the second and third elements and binds them to the variables
address@hidden and @code{y}. Then it evaluates @code{x} and @code{y} and
-adds the results. The @code{call} and @code{fn} patterns similarly
-implement two flavors of function calls. @code{(pred numberp)} is a
-pattern that simply checks that @code{exp} is a number and if so,
-evaluates it. @code{(pred symbolp)} matches symbols, and returns
-their association. Finally, @code{_} 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:
-
address@hidden
-(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
address@hidden example
-
-Additional UPatterns can be defined using the @code{pcase-defmacro}
-macro.
-
address@hidden pcase-defmacro name args &rest body
-Define a new kind of UPattern for @code{pcase}. The new UPattern will
-be invoked as @code{(@var{name} @var{actual-args})}. The @var{body}
-should describe how to rewrite the UPattern @var{name} into some other
-UPattern. The rewriting will be the result of evaluating @var{body}
-in an environment where @var{args} are bound to @var{actual-args}.
address@hidden defmac
-
@node Combining Conditions
@section Constructs for Combining Conditions
@cindex combining conditions
@@ -621,6 +414,757 @@ This is not completely equivalent because it can evaluate
@var{arg1} or
@var{arg3})} never evaluates any argument more than once.
@end defspec
address@hidden Pattern-Matching Conditional
address@hidden Pattern-Matching Conditional
address@hidden pcase
address@hidden pattern matching
+
+Aside from the four basic conditional forms, Emacs Lisp also
+has a pattern-matching conditional form, the @code{pcase} macro,
+a hybrid of @code{cond} and @code{case}
+(@pxref{Conditionals,,,cl,Common Lisp Extensions})
+that overcomes their limitations and introduces
+the @dfn{pattern matching} programming style.
+First, the limitations:
+
address@hidden
address@hidden The @code{cond} form chooses among alternatives
+by evaluating the predicate @var{condition} of each
+of its clauses (@pxref{Conditionals}).
+The primary limitation is that variables let-bound in @var{condition}
+are not available to the clause's @var{body-forms}.
+
+Another annoyance (more an inconvenience than a limitation)
+is that when a series of @var{condition} predicates implement
+equality tests, there is a lot of repeated code.
+For that, why not use @code{case}?
+
address@hidden
+The @code{case} macro chooses among alternatives by evaluating
+the equality of its first argument against a set of specific
+values.
+The limitations are two-fold:
+
address@hidden
address@hidden The equality tests use @code{eql}.
address@hidden The values must be known and written in advance.
address@hidden enumerate
+
address@hidden
+These render @code{case} unsuitable for strings or compound
+data structures (e.g., lists or vectors).
+For that, why not use @code{cond}? Wait, what? @dots{}
address@hidden itemize
+
address@hidden
+Conceptually, the @code{pcase} macro borrows the first-arg focus
+of @code{case} and the clause-processing flow of @code{cond},
+replacing @var{condition} with a generalization of
+the equality test called @dfn{matching},
+and adding facilities so that you can concisely express a
+clause's predicate, and arrange to share let-bindings between
+a clause's predicate and @var{body-forms}.
+
+The concise expression of a predicate is known as a @dfn{pattern}.
+When the predicate, called on the value of the first arg,
+returns address@hidden, the pattern matches the value
+(or sometimes ``the value matches the pattern'').
+
address@hidden
+* The @code{pcase} macro: pcase Macro. Plus examples and caveats.
+* Extending @code{pcase}: Extending pcase. Define new kinds of patterns.
+* Backquote-Style Patterns: Backquote Patterns. Structural matching.
address@hidden menu
+
address@hidden pcase Macro
address@hidden The @code{pcase} macro
+
+For background, @xref{Pattern-Matching Conditional}.
+
address@hidden pcase expression &rest clauses
+Each clause in @var{clauses} has the form:
address@hidden@code{(@var{pattern} @address@hidden)}}.
+
+Evaluate @var{expression} to determine its value, @var{expval}.
+Find the first clause in @var{clauses} whose @var{pattern} matches
address@hidden and pass control to that clause's @var{body-forms}.
+
+If there is a match, the value of @code{pcase} is the value
+of the last of @var{body-forms} in the successful clause.
+Otherwise, @code{pcase} evaluates to @code{nil}.
address@hidden defmac
+
+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:
+
address@hidden @code
+
address@hidden _
+Matches any @var{expval}.
+This is known as @dfn{don't care} or @dfn{wildcard}.
+
address@hidden '@var{val}
+Matches if @var{expval} is @code{equal} to @var{val}.
+
address@hidden @var{keyword}
address@hidden @var{integer}
address@hidden @var{string}
+Matches if @var{expval} is @code{equal} to the literal object.
+This is a special case of @code{'@var{val}}, above,
+possible because literal objects of these types are self-quoting.
+
address@hidden @var{symbol}
+Matches any @var{expval}, and additionally let-binds @var{symbol} to
address@hidden, such that this binding is available to
address@hidden (@pxref{Dynamic Binding}).
+
+If @var{symbol} is part of a sequencing pattern @var{seqpat}
+(e.g., by using @code{and}, below), the binding is also available to
+the portion of @var{seqpat} following the appearance of @var{symbol}.
+This usage has some caveats (@pxref{pcase-symbol-caveats,,caveats}).
+
+Two symbols to avoid are @code{t}, which behaves like @code{_}
+(above) and is deprecated, and @code{nil}, which signals error.
+Likewise, it makes no sense to bind keyword symbols
+(@pxref{Constant Variables}).
+
address@hidden (pred @var{function})
+Matches if the predicate @var{function} returns address@hidden
+when called on @var{expval}.
address@hidden can have one of the possible forms:
+
address@hidden @asis
address@hidden function name (a symbol)
+Call the named function with one argument, @var{expval}.
+
+Example: @code{integerp}
+
address@hidden lambda expression
+Call the anonymous function with one argument,
address@hidden (@pxref{Lambda Expressions}).
+
+Example: @code{(lambda (n) (= 42 n))}
+
address@hidden function call with @var{n} args
+Call the function (the first element of the function call)
+with @var{n} arguments (the other elements) and an additional
address@hidden argument that is @var{expval}.
+
+Example: @code{(= 42)address@hidden
+In this example, the function is @code{=}, @var{n} is one, and
+the actual function call becomes: @address@hidden(= 42 @var{expval})}}.
address@hidden table
+
address@hidden (app @var{function} @var{pattern})
+Matches if @var{function} called on @var{expval} returns a
+value that matches @var{pattern}.
address@hidden can take one of the
+forms described for @code{pred}, above.
+Unlike @code{pred}, however,
address@hidden tests the result against @var{pattern},
+rather than against a boolean truth value.
+
address@hidden (guard @var{boolean-expression})
+Matches if @var{boolean-expression} evaluates to address@hidden
+
address@hidden (let @var{pattern} @var{expr})
+Evaluates @var{expr} to get @var{exprval}
+and matches if @var{exprval} matches @var{pattern}.
+(It is called @code{let} because
address@hidden can bind symbols to values using @var{symbol}.)
address@hidden table
+
address@hidden sequencing pattern
+A @dfn{sequencing pattern} (also known as @var{seqpat}) is a
+pattern that processes its sub-pattern arguments in sequence.
+There are two for @code{pcase}: @code{and} and @code{or}.
+They behave in a similar manner to the special forms
+that share their name (@pxref{Combining Conditions}),
+but instead of processing values, they process sub-patterns.
+
address@hidden @code
address@hidden (and @address@hidden)
+Attempts to match @address@hidden, in order,
+until one of them fails to match.
+In that case, @code{and} likewise fails to match,
+and the rest of the sub-patterns are not tested.
+If all sub-patterns match, @code{and} matches.
+
address@hidden (or @var{pattern1} @address@hidden)
+Attempts to match @var{pattern1}, @var{pattern2}, @dots{}, in order,
+until one of them succeeds.
+In that case, @code{or} likewise matches,
+and the rest of the sub-patterns are not tested.
+(Note that there must be at least two sub-patterns.
+Simply @address@hidden(or @var{pattern1})}} signals error.)
address@hidden Issue: Is this correct and intended?
address@hidden Are there exceptions, qualifications?
address@hidden (Btw, ``Please avoid it'' is a poor error message.)
+
+To present a consistent environment (@pxref{Intro Eval})
+to @var{body-forms} (thus avoiding an evaluation error on match),
+if any of the sub-patterns let-binds a set of symbols,
+they @emph{must} all bind the same set of symbols.
address@hidden table
+
address@hidden
address@hidden Example: Advantage Over @code{case}
+
+Here's an example that highlights some advantages @code{pcase}
+has over @code{case}
+(@pxref{Conditionals,,,cl,Common Lisp Extensions}).
+
address@hidden
address@hidden
+(pcase (get-return-code x)
+ ;; string
+ ((and (pred stringp) msg)
+ (message "%s" msg))
address@hidden group
address@hidden
+ ;; 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"))
address@hidden group
address@hidden
+ ;; default
+ (code (message "Unknown return code %S" code)))
address@hidden group
address@hidden example
+
address@hidden
+With @code{case}, you would need to explicitly declare a local
+variable @code{code} to hold the return value of @code{get-return-code}.
+Also @code{case} is difficult to use with strings because it
+uses @code{eql} for comparison.
+
address@hidden
address@hidden Example: Using @code{and}
+
+A common idiom is to write a pattern starting with @code{and},
+with one or more @var{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.
+
address@hidden
address@hidden
+(and
+ (pred integerp)
+ n ; @r{bind @code{n} to @var{expval}}
+ (guard (<= -9 n 9)))
address@hidden group
address@hidden example
+
address@hidden
+First, @code{pred} matches if @address@hidden(integerp @var{expval})}}
+evaluates to address@hidden
+Next, @code{n} is a @var{symbol} pattern that matches
+anything and binds @code{n} to @var{expval}.
+Lastly, @code{guard} matches if the boolean expression
address@hidden@code{(<= -9 n 9)}} (note the reference to @code{n})
+evaluates to address@hidden
+If all these sub-patterns match, @code{and} matches.
+
address@hidden
address@hidden Example: Reformulation with @code{pcase}
+
+Here is another example that shows how to reformulate a simple
+matching task from its traditional implementation
+(function @code{grok/traditional}) to one using
address@hidden (function @code{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 (@pxref{Regular Expressions}):
+
address@hidden
address@hidden
+(defun grok/traditional (obj)
+ (if (and (stringp obj)
+ (string-match "^key:\\([[:digit:]]+\\)$" obj))
+ (match-string 1 obj)
+ (list "149" 'default)))
address@hidden group
+
address@hidden
+(grok/traditional "key:0") @result{} "0"
+(grok/traditional "key:149") @result{} "149"
+(grok/traditional 'monolith) @result{} ("149" default)
address@hidden group
address@hidden example
+
address@hidden
+The reformulation demonstrates @var{symbol} binding as well as
address@hidden, @code{and}, @code{pred}, @code{app} and @code{let}.
+
address@hidden
address@hidden
+(defun grok/pcase (obj)
+ (pcase obj
+ ((or ; @r{line 1}
+ (and ; @r{line 2}
+ (pred stringp) ; @r{line 3}
+ (pred (string-match ; @r{line 4}
+ "^key:\\([[:digit:]]+\\)$")) ; @r{line 5}
+ (app (match-string 1) ; @r{line 6}
+ val)) ; @r{line 7}
+ (let val (list "149" 'default))) ; @r{line 8}
+ val))) ; @r{line 9}
address@hidden group
+
address@hidden
+(grok/pcase "key:0") @result{} "0"
+(grok/pcase "key:149") @result{} "149"
+(grok/pcase 'monolith) @result{} ("149" default)
address@hidden group
address@hidden example
+
address@hidden
+The bulk of @code{grok/pcase} is a single clause of a @code{pcase}
+form, the pattern on lines 1-8, the (single) body form on line 9.
+The pattern is @code{or}, which tries to match in turn its argument
+sub-patterns, first @code{and} (lines 2-7), then @code{let} (line 8),
+until one of them succeeds.
+
+As in the previous example (@pxref{pcase-example-1,,Example 1}),
address@hidden begins with a @code{pred} sub-pattern to ensure
+the following sub-patterns work with an object of the correct
+type (string, in this case). If @address@hidden(stringp @var{expval})}}
+returns @code{nil}, @code{pred} fails, and thus @code{and} fails, too.
+
+The next @code{pred} (lines 4-5) evaluates
address@hidden@code{(string-match RX @var{expval})}}
+and matches if the result is address@hidden, which means
+that @var{expval} has the desired form: @code{key:NUMBER}.
+Again, failing this, @code{pred} fails and @code{and}, too.
+
+Lastly (in this series of @code{and} sub-patterns), @code{app}
+evaluates @address@hidden(match-string 1 @var{expval})}}
+to get a temporary value @var{tmp} (i.e., the ``NUMBER'' substring)
+and tries to match @var{tmp} against pattern @code{val}.
+Since that is a @var{symbol} pattern, it matches unconditionally
+and additionally binds @code{val} to @var{tmp}.
+
+Now that @code{app} has matched, all @code{and} sub-patterns
+have matched, and so @code{and} matches.
+Likewise, once @code{and} has matched, @code{or} matches
+and does not proceed to try sub-pattern @code{let} (line 9).
+
+Let's consider the situation where @code{obj} is not a string,
+or it is a string but has the wrong form.
+In this case, one of the @code{pred} (lines 3-5) fails to match,
+thus @code{and} (line 2) fails to match,
+thus @code{or} (line 1) proceeds to try sub-pattern @code{let} (line 9).
+
+First, @code{let} evaluates @address@hidden(list "149" 'default)}}
+to get @address@hidden("149" default)}}, the @var{exprval}, and then
+tries to match @var{exprval} against pattern @code{val}.
+Since that is a @var{symbol} pattern, it matches unconditionally
+and additionally binds @code{val} to @var{exprval}.
+Now that @code{let} has matched, @code{or} matches.
+
+Note how both @code{and} and @code{let} sub-patterns finish in the
+same way: by trying (always successfully) to match against the
address@hidden pattern @code{val}, in the process binding @code{val}.
+Thus, @code{or} always matches and control always passes
+to the body form (line 9).
+Because that is the last body form in a successfully matched
address@hidden clause, it is the value of @code{pcase} and likewise
+the return value of @code{grok/pcase} (@pxref{What Is a Function}).
+
address@hidden
address@hidden Caveats for @var{symbol} in Sequencing Patterns
+
+The preceding examples all use sequencing patterns
+which include the @var{symbol}
+sub-pattern in some way.
+Here are some important details about that usage.
+
address@hidden
address@hidden When @var{symbol} occurs more than once in @var{seqpat},
+the second and subsequent occurances do not expand to re-binding,
+but instead expand to an equality test using @code{eq}.
+
+The following example features a @code{pcase} form
+with two clauses and two @var{seqpat}, A and B.
+Both A and B first check that @var{expval} is a
+pair (using @code{pred}),
+and then bind symbols to the @code{car} and @code{cdr}
+of @var{expval} (using one @code{app} each).
+
+For A, because symbol @code{st} is mentioned twice, the second
+mention becomes an equality test using @code{eq}.
+On the other hand, B uses two separate symbols, @code{s1} and
address@hidden, both of which become independent bindings.
+
address@hidden
address@hidden
+(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))
address@hidden group
address@hidden
+ ((and (pred consp) ; seqpat B
+ (app car s1) ; first mention: s1
+ (app cdr s2)) ; first mention: s2
+ (list 'not-eq s1 s2))))
address@hidden group
+
address@hidden
+(let ((s "yow!"))
+ (grok (cons s s))) @result{} (eq "yow!")
+(grok (cons "yo!" "yo!")) @result{} (not-eq "yo!" "yo!")
+(grok '(4 2)) @result{} (not-eq 4 (2))
address@hidden group
address@hidden example
+
address@hidden Side-effecting code referencing @var{symbol} is undefined.
+Avoid.
+For example, here are two similar functions.
+Both use @code{and}, @var{symbol} and @code{guard}:
+
address@hidden
address@hidden
+(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) @result{} (yes 81)
+(square-double-digit-p/CLEAN 3) @result{} (no 9)
address@hidden group
+
address@hidden
+(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) @result{} (yes 81)
+(square-double-digit-p/MAYBE 3) @result{} (yes 9) ; @r{WRONG!}
address@hidden group
address@hidden example
+
address@hidden
+The difference is in @var{boolean-expression} in @code{guard}:
address@hidden references @code{n} simply and directly,
+while @code{MAYBE} references @code{n} with a side-effect,
+in the expression @code{(incf n)}.
+When @code{integer} is 3, here's what happens:
+
address@hidden
address@hidden The first @code{n} binds it to @var{expval},
+i.e., the result of evaluating @code{(* 3 3)}, or 9.
+
address@hidden @var{boolean-expression} is evaluated:
+
address@hidden
address@hidden
+start: (< 9 (incf n) 100)
+becomes: (< 9 (setq n (1+ n)) 100)
+becomes: (< 9 (setq n (1+ 9)) 100)
address@hidden group
address@hidden
+becomes: (< 9 (setq n 10) 100)
+ ; @r{side-effect here!}
+becomes: (< 9 n 100) ; @address@hidden now bound to 10}
+becomes: (< 9 10 100)
+becomes: t
address@hidden group
address@hidden example
+
address@hidden Because the result of the evaluation is address@hidden,
address@hidden matches, @code{and} matches, and
+control passes to that clause's body forms.
address@hidden itemize
+
address@hidden
+Aside from the mathematical incorrectness of asserting that 9 is a
+double-digit integer, there is another problem with @code{MAYBE}.
+The body form references @code{n} once 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
address@hidden patterns entirely, not only
+in @var{boolean-expression} (in @code{guard}),
+but also in @var{expr} (in @code{let})
+and @var{function} (in @code{pred} and @code{app}).
+
address@hidden On match, the clause's body forms can reference the set
+of symbols the pattern let-binds.
+When @var{seqpat} is @code{and}, this set is
+the union of all the symbols each of its sub-patterns let-binds.
+This makes sense because, for @code{and} to match,
+all the sub-patterns must match.
+
+When @var{seqpat} is @code{or}, things are different:
address@hidden 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:
+
address@hidden
address@hidden
+(pcase (read-number "Enter an integer: ")
+ ((or (and (pred evenp)
+ e-num) ; @r{bind @code{e-num} to @var{expval}}
+ o-num) ; @r{bind @code{o-num} to @var{expval}}
+ (list e-num o-num)))
address@hidden group
+
address@hidden
+Enter an integer: 42
address@hidden Symbol’s value as variable is void: o-num
address@hidden group
address@hidden
+Enter an integer: 149
address@hidden Symbol’s value as variable is void: e-num
address@hidden group
address@hidden example
+
address@hidden
+Evaluating body form @address@hidden(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:
+
address@hidden
address@hidden
+(pcase (read-number "Enter an integer: ")
+ ((and num ; @r{line 1}
+ (or (and (pred evenp) ; @r{line 2}
+ (let spin 'even)) ; @r{line 3}
+ (let spin 'odd))) ; @r{line 4}
+ (list spin num))) ; @r{line 5}
address@hidden group
+
address@hidden
+Enter an integer: 42
address@hidden (even 42)
address@hidden group
address@hidden
+Enter an integer: 149
address@hidden (odd 149)
address@hidden group
address@hidden example
+
address@hidden
+Line 1 ``factors out'' the @var{expval} binding with
address@hidden and @var{symbol} (in this case, @code{num}).
+On line 2, @code{or} begins in the same way as before,
+but instead of binding different symbols, uses @code{let} twice
+(lines 3-4) to bind the same symbol @code{spin} in both sub-patterns.
+The value of @code{spin} distinguishes the sub-patterns.
+The body form references both symbols (line 5).
address@hidden enumerate
+
address@hidden Extending pcase
address@hidden Extending @code{pcase}
address@hidden pcase, defining new kinds of patterns
+
+The @code{pcase} macro supports several kinds of patterns
+(@pxref{Pattern-Matching Conditional}).
+You can add support for other kinds of patterns
+using the @code{pcase-defmacro} macro.
+
address@hidden pcase-defmacro name args [doc] &rest body
+Define a new kind of pattern for @code{pcase}, to be invoked
+as @address@hidden(@var{name} @var{actual-args})}}.
+The @code{pcase} macro expands this into a function call
+that evaluates @var{body}, whose job it is to
+rewrite the invoked pattern into some other pattern,
+in an environment where @var{args} are bound to @var{actual-args}.
+
+Additionally, arrange to display @var{doc} along with
+the docstring of @code{pcase}.
+By convention, @var{doc} should use @code{EXPVAL}
+to stand for the result of
+evaluating @var{expression} (first arg to @code{pcase}).
address@hidden defmac
+
address@hidden
+Typically, @var{body} rewrites the invoked pattern
+to use more basic patterns.
+Although all patterns eventually reduce to core patterns,
address@hidden need not use core patterns straight away.
+The following example defines two patterns, named
address@hidden and @code{integer-less-than}.
+
address@hidden
address@hidden
+(pcase-defmacro less-than (n)
+ "Matches if EXPVAL is a number less than N."
+ `(pred (> ,n)))
address@hidden group
+
address@hidden
+(pcase-defmacro integer-less-than (n)
+ "Matches if EXPVAL is an integer less than N."
+ `(and (pred integerp)
+ (less-than ,n)))
address@hidden group
address@hidden example
+
address@hidden
+Note that the docstrings mention @var{args}
+(in this case, only one: @code{n}) in the usual way,
+and also mention @code{EXPVAL} by convention.
+The first rewrite (i.e., @var{body} for @code{less-than})
+uses one core pattern: @code{pred}.
+The second uses two core patterns: @code{and} and @code{pred},
+as well as the newly-defined pattern @code{less-than}.
+Both use a single backquote construct (@pxref{Backquote}).
+
address@hidden Backquote Patterns
address@hidden Backquote-Style Patterns
address@hidden backquote-style patterns
address@hidden matching, structural
address@hidden structural matching
+
+This subsection describes @dfn{backquote-style patterns},
+a set of builtin patterns that eases structural matching.
+For background, @xref{Pattern-Matching Conditional}.
+
address@hidden patterns} are a powerful set of
address@hidden pattern extensions (created using @code{pcase-defmacro})
+that make it easy to match @var{expval} against
+specifications of its @emph{structure}.
+
+For example, to match @var{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:
+
address@hidden
address@hidden
+(and (pred listp)
+ ls
address@hidden group
address@hidden
+ (guard (= 2 (length ls)))
+ (guard (string= "first" (car ls)))
+ (let second-elem (cadr ls)))
address@hidden group
address@hidden example
+
address@hidden
+or you can write the equivalent backquote-style pattern:
+
address@hidden
+`("first" ,second-elem)
address@hidden example
+
address@hidden
+The backquote-style pattern is more concise,
+resembles the structure of @var{expval},
+and avoids binding @code{ls}.
+
+A backquote-style pattern has the form @address@hidden where
address@hidden can have the following forms:
+
address@hidden @code
+
address@hidden (@var{qpat1} . @var{qpat2})
+Matches if @var{expval} is a cons cell whose @code{car}
+matches @var{qpat1} and whose @code{cdr} matches @var{qpat2}.
+This readily generalizes to lists as in
address@hidden@code{(@var{qpat1} @var{qpat2} @dots{})}}.
+
address@hidden address@hidden @var{qpat2} @dots{} @var{qpatm}]
+Matches if @var{expval} is a vector of length @var{m} whose
address@hidden@code{(@var{m}-1)}th elements match @var{qpat1},
address@hidden @dots{} @var{qpatm}, respectively.
+
address@hidden @var{symbol}
address@hidden @var{keyword}
address@hidden @var{integer}
address@hidden @var{string}
+Matches if the corresponding element of @var{expval} is
address@hidden to the specified literal object.
+Note that, aside from @var{symbol}, this is the same set of
+self-quoting literal objects that are acceptable as a core pattern.
+
address@hidden ,@var{pattern}
+Matches if the corresponding element of @var{expval}
+matches @var{pattern}.
+Note that @var{pattern} is any kind that @code{pcase} supports.
+(In the example above, @code{second-elem} is a @var{symbol}
+core pattern; it therefore matches anything,
+and let-binds @code{second-elem}.)
address@hidden table
+
+The @dfn{corresponding element} is the portion of @var{expval}
+that is in the same structural position as the structural position
+of @var{qpat} in the backquote-style pattern.
+(In the example above, the corresponding element of
address@hidden is the second element of @var{expval}.)
+
+Here is an example of using @code{pcase} to implement a simple
+interpreter for a little expression language
+(note that this requires lexical binding for the
+lambda expression in the @code{fn} clause to properly
+capture @code{body} and @code{arg} (@pxref{Lexical Binding}):
+
address@hidden
address@hidden
+(defun evaluate (form env)
+ (pcase form
+ (`(add ,x ,y) (+ (evaluate x env)
+ (evaluate y env)))
address@hidden group
address@hidden
+ (`(call ,fun ,arg) (funcall (evaluate fun env)
+ (evaluate arg env)))
+ (`(fn ,arg ,body) (lambda (val)
+ (evaluate body (cons (cons arg val)
+ env))))
address@hidden group
address@hidden
+ ((pred numberp) form)
+ ((pred symbolp) (cdr (assq form env)))
+ (_ (error "Syntax error: %S" form))))
address@hidden group
address@hidden example
+
address@hidden
+The first three clauses use backquote-style patterns.
address@hidden(add ,x ,y)} is a pattern that checks that @code{form}
+is a three-element list starting with the literal symbol @code{add},
+then extracts the second and third elements and binds them
+to symbols @code{x} and @code{y}, respectively.
+The clause body evaluates @code{x} and @code{y} and adds the results.
+Similarly, the @code{call} clause implements a function call,
+and the @code{fn} clause implements an anonymous function definition.
+
+The remaining clauses use core patterns.
address@hidden(pred numberp)} matches if @code{form} is a number.
+On match, the body evaluates it.
address@hidden(pred symbolp)} matches if @code{form} is a symbol.
+On match, the body looks up the symbol in @code{env} and
+returns its association.
+Finally, @code{_} 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:
+
address@hidden
+(evaluate '(add 1 2) nil) @result{} 3
+(evaluate '(add x y) '((x . 1) (y . 2))) @result{} 3
+(evaluate '(call (fn x (add 1 x)) 2) nil) @result{} 3
+(evaluate '(sub 1 2) nil) @result{} error
address@hidden example
+
@node Iteration
@section Iteration
@cindex iteration
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 6b59e31..6c3182b 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -475,14 +475,11 @@ Control Structures
* Sequencing:: Evaluation in textual order.
* Conditionals:: @code{if}, @code{cond}, @code{when}, @code{unless}.
* Combining Conditions:: @code{and}, @code{or}, @code{not}.
+* Pattern-Matching Conditional:: How to use @code{pcase} and friends.
* Iteration:: @code{while} loops.
* Generators:: Generic sequences and coroutines.
* Nonlocal Exits:: Jumping out of a sequence.
-Conditionals
-
-* Pattern matching case statement:: How to use @code{pcase}.
-
Nonlocal Exits
* Catch and Throw:: Nonlocal exits for the program's own purposes.
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 38e434d..fa7b1de 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -110,56 +110,41 @@
(defmacro pcase (exp &rest cases)
"Evaluate EXP to get EXPVAL; try passing control to one of CASES.
CASES is a list of elements of the form (PATTERN CODE...).
-
-A structural PATTERN describes a template that identifies a class
-of values. For example, the pattern \\=`(,foo ,bar) matches any
-two element list, binding its elements to symbols named `foo' and
-`bar' -- in much the same way that `cl-destructuring-bind' would.
-
-A significant difference from `cl-destructuring-bind' is that, if
-a pattern match fails, the next case is tried until either a
-successful match is found or there are no more cases. The CODE
-expression corresponding to the matching pattern determines the
-return value. If there is no match the returned value is nil.
-
-Another difference is that pattern elements may be quoted,
-meaning they must match exactly: The pattern \\='(foo bar)
-matches only against two element lists containing the symbols
-`foo' and `bar' in that order. (As a short-hand, atoms always
-match themselves, such as numbers or strings, and need not be
-quoted.)
-
-Lastly, a pattern can be logical, such as (pred numberp), that
-matches any number-like element; or the symbol `_', that matches
-anything. Also, when patterns are backquoted, a comma may be
-used to introduce logical patterns inside backquoted patterns.
-
-The complete list of standard patterns is as follows:
-
- _ matches anything.
- SYMBOL matches anything and binds it to SYMBOL.
- If a SYMBOL is used twice in the same pattern
- the second occurrence becomes an `eq'uality test.
- (or PAT...) matches if any of the patterns matches.
- (and PAT...) matches if all the patterns match.
- \\='VAL matches if the object is `equal' to VAL.
- ATOM is a shorthand for \\='ATOM.
- ATOM can be a keyword, an integer, or a string.
- (pred FUN) matches if FUN applied to the object returns non-nil.
- (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil.
- (let PAT EXP) matches if EXP matches PAT.
- (app FUN PAT) matches if FUN applied to the object matches PAT.
+For the first CASE whose PATTERN \"matches\" EXPVAL,
+evaluate its CODE..., and return the value of the last form.
+If no CASE has a PATTERN that matches, return nil.
+
+Each PATTERN expands, in essence, to a predicate to call
+on EXPVAL. When the return value of that call is non-nil,
+PATTERN matches. PATTERN can take one of the forms:
+
+ _ matches anything.
+ \\='VAL matches if EXPVAL is `equal' to VAL.
+ KEYWORD shorthand for \\='KEYWORD
+ INTEGER shorthand for \\='INTEGER
+ STRING shorthand for \\='STRING
+ SYMBOL matches anything and binds it to SYMBOL.
+ If a SYMBOL is used twice in the same pattern
+ the second occurrence becomes an `eq'uality test.
+ (pred FUN) matches if FUN called on EXPVAL returns non-nil.
+ (app FUN PAT) matches if FUN called on EXPVAL matches PAT.
+ (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil.
+ (let PAT EXPR) matches if EXPR matches PAT.
+ (and PAT...) matches if all the patterns match.
+ (or PAT...) matches if any of the patterns matches.
+
+FUN in `pred' and `app' can take one of the forms:
+ SYMBOL or (lambda ARGS BODY)
+ call it with one argument
+ (F ARG1 .. ARGn)
+ call F with ARG1..ARGn and EXPVAL as n+1'th argument
+
+FUN, BOOLEXP, EXPR, and subsequent PAT can refer to variables
+bound earlier in the pattern by a SYMBOL pattern.
Additional patterns can be defined using `pcase-defmacro'.
-The FUN argument in the `app' pattern may have the following forms:
- SYMBOL or (lambda ARGS BODY) in which case it's called with one argument.
- (F ARG1 .. ARGn) in which case F gets called with an n+1'th argument
- which is the value being matched.
-So a FUN of the form SYMBOL is equivalent to (FUN).
-FUN can refer to variables bound earlier in the pattern.
-
-See Info node `(elisp) Pattern matching case statement' in the
+See Info node `(elisp) Pattern-Matching Conditional' in the
Emacs Lisp manual for more information and examples."
(declare (indent 1) (debug (form &rest (pcase-PAT body))))
;; We want to use a weak hash table as a cache, but the key will unavoidably
@@ -926,14 +911,29 @@ Otherwise, it defers to REST which is a list of branches
of the form
sexp))
(pcase-defmacro \` (qpat)
- "Backquote-style pcase patterns.
+ "Backquote-style pcase patterns: \\=`QPAT
QPAT can take the following forms:
(QPAT1 . QPAT2) matches if QPAT1 matches the car and QPAT2 the cdr.
[QPAT1 QPAT2..QPATn] matches a vector of length n and QPAT1..QPATn match
its 0..(n-1)th elements, respectively.
- ,PAT matches if the pcase pattern PAT matches.
- ATOM matches if the object is `equal' to ATOM.
- ATOM can be a symbol, an integer, or a string."
+ ,PAT matches if the `pcase' pattern PAT matches.
+ SYMBOL matches if EXPVAL is `equal' to SYMBOL.
+ KEYWORD likewise for KEYWORD.
+ INTEGER likewise for INTEGER.
+ STRING likewise for STRING.
+
+The list or vector QPAT is a template. The predicate formed
+by a backquote-style pattern is a combination of those
+formed by any sub-patterns, wrapped in a top-level condition:
+EXPVAL must be \"congruent\" with the template. For example:
+
+ \\=`(technical ,forum)
+
+The predicate is the logical-AND of:
+ - Is EXPVAL a list of two elements?
+ - Is the first element the symbol `technical'?
+ - True! (The second element can be anything, and for the sake
+ of the body forms, its value is bound to the symbol `forum'.)"
(declare (debug (pcase-QPAT)))
(cond
((eq (car-safe qpat) '\,) (cadr qpat))