Improve documentation of destructuring-binding macros

* lisp/emacs-lisp/pcase.el (pcase-dolist, pcase-let)
(pcase-let*): Improve the doc strings.

* doc/lispref/sequences.texi (Sequence Functions): Improve
wording and rename arguments of seq-let to be more
descriptive.  Add a cross-reference to "Destructuring with
pcase Patterns".
* doc/lispref/control.texi (Pattern-Matching Conditional):
Improve wording and the menu.
(pcase Macro): Incorporate patch suggested by Paul Eggert
<eggert@cs.ucla.edu>.  Reformat text.
(Destructuring with pcase Patterns): Rename from
"Destructuring patterns", and improve wording and indexing.
This commit is contained in:
Eli Zaretskii 2018-11-03 15:11:33 +02:00
parent 74bc0e16b7
commit e824c914da
3 changed files with 159 additions and 130 deletions

View file

@ -419,65 +419,68 @@ This is not completely equivalent because it can evaluate @var{arg1} or
@node Pattern-Matching Conditional @node Pattern-Matching Conditional
@section Pattern-Matching Conditional @section Pattern-Matching Conditional
@cindex pcase @cindex pcase
@cindex pattern matching @cindex pattern matching, programming style
Aside from the four basic conditional forms, Emacs Lisp also Aside from the four basic conditional forms, Emacs Lisp also
has a pattern-matching conditional form, the @code{pcase} macro, has a pattern-matching conditional form, the @code{pcase} macro,
a hybrid of @code{cond} and @code{cl-case} a hybrid of @code{cond} and @code{cl-case}
(@pxref{Conditionals,,,cl,Common Lisp Extensions}) (@pxref{Conditionals,,,cl,Common Lisp Extensions})
that overcomes their limitations and introduces that overcomes their limitations and introduces
the @dfn{pattern matching} programming style. the @dfn{pattern matching programming style}.
First, the limitations: The limitations that @code{pcase} overcomes are:
@itemize @itemize
@item The @code{cond} form chooses among alternatives @item
by evaluating the predicate @var{condition} of each The @code{cond} form chooses among alternatives by evaluating the
of its clauses (@pxref{Conditionals}). predicate @var{condition} of each of its clauses
The primary limitation is that variables let-bound in @var{condition} (@pxref{Conditionals}). The primary limitation is that variables
are not available to the clause's @var{body-forms}. let-bound in @var{condition} are not available to the clause's
@var{body-forms}.
Another annoyance (more an inconvenience than a limitation) Another annoyance (more an inconvenience than a limitation)
is that when a series of @var{condition} predicates implement is that when a series of @var{condition} predicates implement
equality tests, there is a lot of repeated code. equality tests, there is a lot of repeated code. (@code{cl-case}
For that, why not use @code{cl-case}? solves this inconvenience.)
@item @item
The @code{cl-case} macro chooses among alternatives by evaluating The @code{cl-case} macro chooses among alternatives by evaluating
the equality of its first argument against a set of specific the equality of its first argument against a set of specific
values. values.
The limitations are two-fold:
Its limitations are two-fold:
@enumerate @enumerate
@item The equality tests use @code{eql}. @item
@item The values must be known and written in advance. The equality tests use @code{eql}.
@item
The values must be known and written in advance.
@end enumerate @end enumerate
@noindent @noindent
These render @code{cl-case} unsuitable for strings or compound These render @code{cl-case} unsuitable for strings or compound
data structures (e.g., lists or vectors). data structures (e.g., lists or vectors). (@code{cond} doesn't have
For that, why not use @code{cond}? these limitations, but it has others, see above.)
(And here we end up in a circle.)
@end itemize @end itemize
@noindent @noindent
Conceptually, the @code{pcase} macro borrows the first-arg focus Conceptually, the @code{pcase} macro borrows the first-arg focus
of @code{cl-case} and the clause-processing flow of @code{cond}, of @code{cl-case} and the clause-processing flow of @code{cond},
replacing @var{condition} with a generalization of replacing @var{condition} with a generalization of
the equality test called @dfn{matching}, the equality test which is a variant of @dfn{pattern matching},
and adding facilities so that you can concisely express a and adding facilities so that you can concisely express a
clause's predicate, and arrange to share let-bindings between clause's predicate, and arrange to share let-bindings between
a clause's predicate and @var{body-forms}. a clause's predicate and @var{body-forms}.
The concise expression of a predicate is known as a @dfn{pattern}. The concise expression of a predicate is known as a @dfn{pattern}.
When the predicate, called on the value of the first arg, When the predicate, called on the value of the first arg, returns
returns non-@code{nil}, the pattern matches the value non-@code{nil}, we say that ``the pattern matches the value'' (or
(or sometimes ``the value matches the pattern''). sometimes ``the value matches the pattern'').
@menu @menu
* The @code{pcase} macro: pcase Macro. Plus examples and caveats. * The @code{pcase} macro: pcase Macro. Includes examples and caveats.
* Extending @code{pcase}: Extending pcase. Define new kinds of patterns. * Extending @code{pcase}: Extending pcase. Define new kinds of patterns.
* Backquote-Style Patterns: Backquote Patterns. Structural matching. * Backquote-Style Patterns: Backquote Patterns. Structural patterns matching.
* Destructuring patterns:: Using pcase patterns to extract subfields. * Destructuring with pcase Patterns:: Using pcase patterns to extract subfields.
@end menu @end menu
@node pcase Macro @node pcase Macro
@ -498,30 +501,30 @@ of the last of @var{body-forms} in the successful clause.
Otherwise, @code{pcase} evaluates to @code{nil}. Otherwise, @code{pcase} evaluates to @code{nil}.
@end defmac @end defmac
Each @var{pattern} has to be a @dfn{pcase pattern}, which can either @cindex pcase pattern
use one of the core patterns defined below, or use one of the patterns Each @var{pattern} has to be a @dfn{pcase pattern}, which can use
defined via @code{pcase-defmacro}. either one of the core patterns defined below, or one of the patterns
defined via @code{pcase-defmacro} (@pxref{Extending pcase}).
The rest of this subsection The rest of this subsection describes different forms of core
describes different forms of core patterns, patterns, presents some examples, and concludes with important caveats
presents some examples, on using the let-binding facility provided by some pattern forms. A
and concludes with important caveats on using the core pattern can have the following forms:
let-binding facility provided by some pattern forms.
A core pattern can have the following forms:
@table @code @table @code
@item _ @item _
Matches any @var{expval}. Matches any @var{expval}.
This is known as @dfn{don't care} or @dfn{wildcard}. This is also known as @dfn{don't care} or @dfn{wildcard}.
@item '@var{val} @item '@var{val}
Matches if @var{expval} is @code{equal} to @var{val}. Matches if @var{expval} is equals @var{val}. The comparison is done
as if by @code{equal} (@pxref{Equality Predicates}).
@item @var{keyword} @item @var{keyword}
@itemx @var{integer} @itemx @var{integer}
@itemx @var{string} @itemx @var{string}
Matches if @var{expval} is @code{equal} to the literal object. Matches if @var{expval} equals the literal object.
This is a special case of @code{'@var{val}}, above, This is a special case of @code{'@var{val}}, above,
possible because literal objects of these types are self-quoting. possible because literal objects of these types are self-quoting.
@ -533,17 +536,17 @@ Matches any @var{expval}, and additionally let-binds @var{symbol} to
If @var{symbol} is part of a sequencing pattern @var{seqpat} If @var{symbol} is part of a sequencing pattern @var{seqpat}
(e.g., by using @code{and}, below), the binding is also available to (e.g., by using @code{and}, below), the binding is also available to
the portion of @var{seqpat} following the appearance of @var{symbol}. the portion of @var{seqpat} following the appearance of @var{symbol}.
This usage has some caveats (@pxref{pcase-symbol-caveats,,caveats}). This usage has some caveats, see @ref{pcase-symbol-caveats,,caveats}.
Two symbols to avoid are @code{t}, which behaves like @code{_} Two symbols to avoid are @code{t}, which behaves like @code{_}
(above) and is deprecated, and @code{nil}, which signals error. (above) and is deprecated, and @code{nil}, which signals an error.
Likewise, it makes no sense to bind keyword symbols Likewise, it makes no sense to bind keyword symbols
(@pxref{Constant Variables}). (@pxref{Constant Variables}).
@item (pred @var{function}) @item (pred @var{function})
Matches if the predicate @var{function} returns non-@code{nil} Matches if the predicate @var{function} returns non-@code{nil}
when called on @var{expval}. when called on @var{expval}.
@var{function} can have one of the possible forms: the predicate @var{function} can have one of the following forms:
@table @asis @table @asis
@item function name (a symbol) @item function name (a symbol)
@ -570,20 +573,17 @@ the actual function call becomes: @w{@code{(= 42 @var{expval})}}.
@item (app @var{function} @var{pattern}) @item (app @var{function} @var{pattern})
Matches if @var{function} called on @var{expval} returns a Matches if @var{function} called on @var{expval} returns a
value that matches @var{pattern}. value that matches @var{pattern}.
@var{function} can take one of the @var{function} can take one of the forms described for @code{pred},
forms described for @code{pred}, above. above. Unlike @code{pred}, however, @code{app} tests the result
Unlike @code{pred}, however, against @var{pattern}, rather than against a boolean truth value.
@code{app} tests the result against @var{pattern},
rather than against a boolean truth value.
@item (guard @var{boolean-expression}) @item (guard @var{boolean-expression})
Matches if @var{boolean-expression} evaluates to non-@code{nil}. Matches if @var{boolean-expression} evaluates to non-@code{nil}.
@item (let @var{pattern} @var{expr}) @item (let @var{pattern} @var{expr})
Evaluates @var{expr} to get @var{exprval} Evaluates @var{expr} to get @var{exprval} and matches if @var{exprval}
and matches if @var{exprval} matches @var{pattern}. matches @var{pattern}. (It is called @code{let} because @var{pattern}
(It is called @code{let} because can bind symbols to values using @var{symbol}.)
@var{pattern} can bind symbols to values using @var{symbol}.)
@end table @end table
@cindex sequencing pattern @cindex sequencing pattern
@ -596,18 +596,16 @@ but instead of processing values, they process sub-patterns.
@table @code @table @code
@item (and @var{pattern1}@dots{}) @item (and @var{pattern1}@dots{})
Attempts to match @var{pattern1}@dots{}, in order, Attempts to match @var{pattern1}@dots{}, in order, until one of them
until one of them fails to match. fails to match. In that case, @code{and} likewise fails to match, and
In that case, @code{and} likewise fails to match, the rest of the sub-patterns are not tested. If all sub-patterns
and the rest of the sub-patterns are not tested. match, @code{and} matches.
If all sub-patterns match, @code{and} matches.
@item (or @var{pattern1} @var{pattern2}@dots{}) @item (or @var{pattern1} @var{pattern2}@dots{})
Attempts to match @var{pattern1}, @var{pattern2}, @dots{}, in order, Attempts to match @var{pattern1}, @var{pattern2}, @dots{}, in order,
until one of them succeeds. until one of them succeeds. In that case, @code{or} likewise matches,
In that case, @code{or} likewise matches, and the rest of the sub-patterns are not tested. (Note that there
and the rest of the sub-patterns are not tested. must be at least two sub-patterns.
(Note that there must be at least two sub-patterns.
Simply @w{@code{(or @var{pattern1})}} signals error.) Simply @w{@code{(or @var{pattern1})}} signals error.)
@c Issue: Is this correct and intended? @c Issue: Is this correct and intended?
@c Are there exceptions, qualifications? @c Are there exceptions, qualifications?
@ -1042,12 +1040,11 @@ Both use a single backquote construct (@pxref{Backquote}).
This subsection describes @dfn{backquote-style patterns}, This subsection describes @dfn{backquote-style patterns},
a set of builtin patterns that eases structural matching. a set of builtin patterns that eases structural matching.
For background, @xref{Pattern-Matching Conditional}. For background, @pxref{Pattern-Matching Conditional}.
@dfn{Backquote-style patterns} are a powerful set of Backquote-style patterns are a powerful set of @code{pcase} pattern
@code{pcase} pattern extensions (created using @code{pcase-defmacro}) extensions (created using @code{pcase-defmacro}) that make it easy to
that make it easy to match @var{expval} against match @var{expval} against specifications of its @emph{structure}.
specifications of its @emph{structure}.
For example, to match @var{expval} that must be a list of two For example, to match @var{expval} that must be a list of two
elements whose first element is a specific string and the second elements whose first element is a specific string and the second
@ -1173,87 +1170,102 @@ evaluation results:
(evaluate '(sub 1 2) nil) @result{} error (evaluate '(sub 1 2) nil) @result{} error
@end example @end example
@node Destructuring patterns @node Destructuring with pcase Patterns
@subsection Destructuring Patterns @subsection Destructuring with @code{pcase} Patterns
@cindex destructuring patterns @cindex destructuring with pcase patterns
Pcase patterns not only express a condition on the form of the objects Pcase patterns not only express a condition on the form of the objects
they can match but they can also extract sub-fields of those objects. they can match, but they can also extract sub-fields of those objects.
Say we have a list and want to extract 2 elements from it with the For example we can extract 2 elements from a list that is the value of
following code: the variable @code{my-list} with the following code:
@example @example
(pcase l (pcase my-list
(`(add ,x ,y) (message "Contains %S and %S" x y))) (`(add ,x ,y) (message "Contains %S and %S" x y)))
@end example @end example
This will not only extract @code{x} and @code{y} but will additionally This will not only extract @code{x} and @code{y} but will additionally
test that @code{l} is a list containing exactly 3 elements and whose test that @code{my-list} is a list containing exactly 3 elements and
first element is the symbol @code{add}. If any of those tests fail, whose first element is the symbol @code{add}. If any of those tests
@code{pcase} will directly return @code{nil} without calling fail, @code{pcase} will immediately return @code{nil} without calling
@code{message}. @code{message}.
@dfn{Destructuring} of an object is an operation that extracts Extraction of multiple values stored in an object is known as
multiple values stored in the object, e.g., the 2nd and the 3rd @dfn{destructuring}. Using @code{pcase} patterns allows to perform
element of a list or a vector. @dfn{Destructuring binding} is @dfn{destructuring binding}, which is similar to a local binding
similar to a local binding (@pxref{Local Variables}), but it gives (@pxref{Local Variables}), but gives values to multiple elements of
values to multiple elements of a variable by extracting those values a variable by extracting those values from an object of compatible
from an object of compatible structure. structure.
The macros described in this section use @dfn{destructuring The macros described in this section use @code{pcase} patterns to
patterns}, which are normal Pcase patterns used in a context where we perform destructuring binding. The condition of the object to be of
presume that the object does match the pattern, and we only want compatible structure means that the object must match the pattern,
to extract some subfields. For example: because only then the object's subfields can be extracted. For
example:
@example @example
(pcase-let ((`(add ,x ,y) l)) (pcase-let ((`(add ,x ,y) my-list))
(message "Contains %S and %S" x y)) (message "Contains %S and %S" x y))
@end example @end example
@noindent @noindent
does the same as the previous example, except that it directly tries does the same as the previous example, except that it directly tries
to extract @code{x} and @code{y} from @code{l} without first verifying to extract @code{x} and @code{y} from @code{my-list} without first
if @code{l} is a list which has the right number of elements and has verifying if @code{my-list} is a list which has the right number of
@code{add} as its first element. elements and has @code{add} as its first element. The precise
The precise behavior when the object does not actually match the behavior when the object does not actually match the pattern is
pattern is undefined, although the body will not be silently skipped: undefined, although the body will not be silently skipped: either an
either an error is signaled or the body is run with some of the error is signaled or the body is run with some of the variables
variables potentially bound to arbitrary values like @code{nil}. potentially bound to arbitrary values like @code{nil}.
The pcase patterns that are useful for destructuring bindings are
generally those described in @ref{Backquote Patterns}, since they
express a specification of the structure of objects that will match.
For an alternative facility for destructuring binding, see
@ref{seq-let}.
@defmac pcase-let bindings body@dots{} @defmac pcase-let bindings body@dots{}
Bind variables according to @var{bindings} and then eval @var{body}. Perform desctructuring binding of variables according to
@var{bindings}, and then evaluate @var{body}.
@var{bindings} is a list of bindings of the form @w{@code{(@var{pattern} @var{bindings} is a list of bindings of the form @w{@code{(@var{pattern}
@var{exp})}}, where @var{exp} is an expression to evaluate and @var{exp})}}, where @var{exp} is an expression to evaluate and
@var{pattern} is a destructuring pattern. @var{pattern} is a @code{pcase} pattern.
All @var{exp}s are evaluated first after which they are matched All @var{exp}s are evaluated first, after which they are matched
against their respective @var{pattern}, introducing new variable against their respective @var{pattern}, introducing new variable
bindings which can then be used inside @var{body}. bindings that can then be used inside @var{body}. The variable
bindings are produced by destructuring binding of elements of
@var{pattern} to the values of the corresponding elements of the
evaluated @var{exp}.
@end defmac @end defmac
@defmac pcase-let* bindings body@dots{} @defmac pcase-let* bindings body@dots{}
Bind variables according to @var{bindings} and then eval @var{body}. Perform desctructuring binding of variables according to
@var{bindings}, and then evaluate @var{body}.
@var{bindings} is a list of bindings of the form @code{(@var{pattern} @var{bindings} is a list of bindings of the form @code{(@var{pattern}
@var{exp})}, where @var{exp} is an expression to evaluate and @var{exp})}, where @var{exp} is an expression to evaluate and
@var{pattern} is a destructuring pattern. @var{pattern} is a @code{pcase} pattern. The variable bindings are
produced by destructuring binding of elements of @var{pattern} to the
values of the corresponding elements of the evaluated @var{exp}.
Unlike @code{pcase-let}, but like @code{let*}, each @var{exp} is Unlike @code{pcase-let}, but similarly to @code{let*}, each @var{exp}
matched against its corresponding @var{pattern} before passing to the is matched against its corresponding @var{pattern} before processing
next element of @var{bindings}, so the variables introduced in each the next element of @var{bindings}, so the variable bindings
binding are available in the @var{exp}s that follow it, additionally introduced in each one of the @var{bindings} are available in the
to being available in @var{body}. @var{exp}s of the @var{bindings} that follow it, additionally to
being available in @var{body}.
@end defmac @end defmac
@findex dolist
@defmac pcase-dolist (pattern list) body@dots{} @defmac pcase-dolist (pattern list) body@dots{}
This construct executes @var{body} once for each element of Execute @var{body} once for each element of @var{list}, on each
@var{list}, in a context where the variables appearing in the the iteration performing a destructuring binding of variables in
destructuring pattern @var{pattern} are bound to the corresponding @var{pattern} to the values of the corresponding subfields of the
values found in the element. element of @var{list}. The bindings are performed as if by
When @var{pattern} is a simple variable, this ends up being equivalent @code{pcase-let}. When @var{pattern} is a simple variable, this ends
to @code{dolist}. up being equivalent to @code{dolist} (@pxref{Iteration}).
@end defmac @end defmac

View file

@ -1049,15 +1049,18 @@ that @var{sequence} can be a list, vector or string. This is
primarily useful for side-effects. primarily useful for side-effects.
@end defmac @end defmac
@defmac seq-let arguments sequence body@dots{} @anchor{seq-let}
@defmac seq-let var-sequence val-sequence body@dots{}
@cindex sequence destructuring @cindex sequence destructuring
This macro binds the variables defined in @var{arguments} to the This macro binds the variables defined in @var{var-sequence} to the
elements of @var{sequence}. @var{arguments} can themselves include values that are the corresponding elements of @var{val-sequence}.
sequences, allowing for nested destructuring. This is known as @dfn{destructuring binding}. The elements of
@var{var-sequence} can themselves include sequences, allowing for
nested destructuring.
The @var{arguments} sequence can also include the @code{&rest} marker The @var{var-sequence} sequence can also include the @code{&rest}
followed by a variable name to be bound to the rest of marker followed by a variable name to be bound to the rest of
@code{sequence}. @var{val-sequence}.
@example @example
@group @group
@ -1081,6 +1084,9 @@ followed by a variable name to be bound to the rest of
@end group @end group
@result{} [3 4] @result{} [3 4]
@end example @end example
The @code{pcase} patterns provide an alternative facility for
destructuring binding, see @ref{Destructuring with pcase Patterns}.
@end defmac @end defmac
@defun seq-random-elt sequence @defun seq-random-elt sequence

View file

@ -264,10 +264,14 @@ variable name being but a special case of it)."
;;;###autoload ;;;###autoload
(defmacro pcase-let* (bindings &rest body) (defmacro pcase-let* (bindings &rest body)
"Like `let*' but where you can use `pcase' patterns for bindings. "Like `let*', but supports destructuring BINDINGS using `pcase' patterns.
BODY should be an expression, and BINDINGS should be a list of bindings As with `pcase-let', BINDINGS are of the form (PATTERN EXP), but the
of the form (PATTERN EXP). EXP in each binding in BINDINGS can use the results of the destructuring
See `pcase-let' for discussion of how PATTERN is matched." bindings that precede it in BINDINGS' order.
Each EXP should match (i.e. be of compatible structure) to its
respective PATTERN; a mismatch may signal an error or may go
undetected, binding variables to arbitrary values, such as nil."
(declare (indent 1) (declare (indent 1)
(debug ((&rest (pcase-PAT &optional form)) body))) (debug ((&rest (pcase-PAT &optional form)) body)))
(let ((cached (gethash bindings pcase--memoize))) (let ((cached (gethash bindings pcase--memoize)))
@ -280,13 +284,16 @@ See `pcase-let' for discussion of how PATTERN is matched."
;;;###autoload ;;;###autoload
(defmacro pcase-let (bindings &rest body) (defmacro pcase-let (bindings &rest body)
"Like `let' but where you can use `pcase' patterns for bindings. "Like `let', but supports destructuring BINDINGS using `pcase' patterns.
BODY should be a list of expressions, and BINDINGS should be a list of bindings BODY should be a list of expressions, and BINDINGS should be a list of
of the form (PATTERN EXP). bindings of the form (PATTERN EXP).
The PATTERNs are only used to extract data, so the code does not test All EXPs are evaluated first, and then used to perform destructuring
whether the data does match the corresponding patterns: a mismatch bindings by matching each EXP against its respective PATTERN. Then
may signal an error or may go undetected, binding variables to arbitrary BODY is evaluated with those bindings in effect.
values, such as nil."
Each EXP should match (i.e. be of compatible structure) to its
respective PATTERN; a mismatch may signal an error or may go
undetected, binding variables to arbitrary values, such as nil."
(declare (indent 1) (debug pcase-let*)) (declare (indent 1) (debug pcase-let*))
(if (null (cdr bindings)) (if (null (cdr bindings))
`(pcase-let* ,bindings ,@body) `(pcase-let* ,bindings ,@body)
@ -304,11 +311,15 @@ values, such as nil."
;;;###autoload ;;;###autoload
(defmacro pcase-dolist (spec &rest body) (defmacro pcase-dolist (spec &rest body)
"Superset of `dolist' where the VAR binding can be a `pcase' PATTERN. "Eval BODY once for each set of bindings defined by PATTERN and LIST elements.
More specifically, this is just a shorthand for the following combination PATTERN should be a `pcase' pattern describing the structure of
of `dolist' and `pcase-let': LIST elements, and LIST is a list of objects that match PATTERN,
i.e. have a structure that is compatible with PATTERN.
(dolist (x LIST) (pcase-let ((PATTERN x)) BODY...)) For each element of LIST, this macro binds the variables in
PATTERN to the corresponding subfields of the LIST element, and
then evaluates BODY with these bindings in effect. The
destructuring bindings of variables in PATTERN to the subfields
of the elements of LIST is performed as if by `pcase-let'.
\n(fn (PATTERN LIST) BODY...)" \n(fn (PATTERN LIST) BODY...)"
(declare (indent 1) (debug ((pcase-PAT form) body))) (declare (indent 1) (debug ((pcase-PAT form) body)))
(if (pcase--trivial-upat-p (car spec)) (if (pcase--trivial-upat-p (car spec))