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
@section Pattern-Matching Conditional
@cindex pcase
@cindex pattern matching
@cindex pattern matching, programming style
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{cl-case}
(@pxref{Conditionals,,,cl,Common Lisp Extensions})
that overcomes their limitations and introduces
the @dfn{pattern matching} programming style.
First, the limitations:
the @dfn{pattern matching programming style}.
The limitations that @code{pcase} overcomes are:
@itemize
@item 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}.
@item
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{cl-case}?
equality tests, there is a lot of repeated code. (@code{cl-case}
solves this inconvenience.)
@item
The @code{cl-case} macro chooses among alternatives by evaluating
the equality of its first argument against a set of specific
values.
The limitations are two-fold:
Its limitations are two-fold:
@enumerate
@item The equality tests use @code{eql}.
@item The values must be known and written in advance.
@item
The equality tests use @code{eql}.
@item
The values must be known and written in advance.
@end enumerate
@noindent
These render @code{cl-case} unsuitable for strings or compound
data structures (e.g., lists or vectors).
For that, why not use @code{cond}?
(And here we end up in a circle.)
data structures (e.g., lists or vectors). (@code{cond} doesn't have
these limitations, but it has others, see above.)
@end itemize
@noindent
Conceptually, the @code{pcase} macro borrows the first-arg focus
of @code{cl-case} and the clause-processing flow of @code{cond},
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
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 non-@code{nil}, the pattern matches the value
(or sometimes ``the value matches the pattern'').
When the predicate, called on the value of the first arg, returns
non-@code{nil}, we say that ``the pattern matches the value'' (or
sometimes ``the value matches the pattern'').
@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.
* Backquote-Style Patterns: Backquote Patterns. Structural matching.
* Destructuring patterns:: Using pcase patterns to extract subfields.
* Backquote-Style Patterns: Backquote Patterns. Structural patterns matching.
* Destructuring with pcase Patterns:: Using pcase patterns to extract subfields.
@end menu
@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}.
@end defmac
Each @var{pattern} has to be a @dfn{pcase pattern}, which can either
use one of the core patterns defined below, or use one of the patterns
defined via @code{pcase-defmacro}.
@cindex pcase pattern
Each @var{pattern} has to be a @dfn{pcase pattern}, which can use
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
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:
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:
@table @code
@item _
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}
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}
@itemx @var{integer}
@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,
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}
(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}).
This usage has some caveats, see @ref{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.
(above) and is deprecated, and @code{nil}, which signals an error.
Likewise, it makes no sense to bind keyword symbols
(@pxref{Constant Variables}).
@item (pred @var{function})
Matches if the predicate @var{function} returns non-@code{nil}
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
@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})
Matches if @var{function} called on @var{expval} returns a
value that matches @var{pattern}.
@var{function} can take one of the
forms described for @code{pred}, above.
Unlike @code{pred}, however,
@code{app} tests the result against @var{pattern},
rather than against a boolean truth value.
@var{function} can take one of the forms described for @code{pred},
above. Unlike @code{pred}, however, @code{app} tests the result
against @var{pattern}, rather than against a boolean truth value.
@item (guard @var{boolean-expression})
Matches if @var{boolean-expression} evaluates to non-@code{nil}.
@item (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
@var{pattern} can bind symbols to values using @var{symbol}.)
Evaluates @var{expr} to get @var{exprval} and matches if @var{exprval}
matches @var{pattern}. (It is called @code{let} because @var{pattern}
can bind symbols to values using @var{symbol}.)
@end table
@cindex sequencing pattern
@ -596,18 +596,16 @@ but instead of processing values, they process sub-patterns.
@table @code
@item (and @var{pattern1}@dots{})
Attempts to match @var{pattern1}@dots{}, 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.
Attempts to match @var{pattern1}@dots{}, 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.
@item (or @var{pattern1} @var{pattern2}@dots{})
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.
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 @w{@code{(or @var{pattern1})}} signals error.)
@c Issue: Is this correct and intended?
@c Are there exceptions, qualifications?
@ -1042,12 +1040,11 @@ Both use a single backquote construct (@pxref{Backquote}).
This subsection describes @dfn{backquote-style patterns},
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
@code{pcase} pattern extensions (created using @code{pcase-defmacro})
that make it easy to match @var{expval} against
specifications of its @emph{structure}.
Backquote-style patterns are a powerful set of @code{pcase} 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
@ -1173,87 +1170,102 @@ evaluation results:
(evaluate '(sub 1 2) nil) @result{} error
@end example
@node Destructuring patterns
@subsection Destructuring Patterns
@cindex destructuring patterns
@node Destructuring with pcase Patterns
@subsection Destructuring with @code{pcase} Patterns
@cindex destructuring with pcase patterns
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.
Say we have a list and want to extract 2 elements from it with the
following code:
they can match, but they can also extract sub-fields of those objects.
For example we can extract 2 elements from a list that is the value of
the variable @code{my-list} with the following code:
@example
(pcase l
(pcase my-list
(`(add ,x ,y) (message "Contains %S and %S" x y)))
@end example
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
first element is the symbol @code{add}. If any of those tests fail,
@code{pcase} will directly return @code{nil} without calling
test that @code{my-list} is a list containing exactly 3 elements and
whose first element is the symbol @code{add}. If any of those tests
fail, @code{pcase} will immediately return @code{nil} without calling
@code{message}.
@dfn{Destructuring} of an object is an operation that extracts
multiple values stored in the object, e.g., the 2nd and the 3rd
element of a list or a vector. @dfn{Destructuring binding} is
similar to a local binding (@pxref{Local Variables}), but it gives
values to multiple elements of a variable by extracting those values
from an object of compatible structure.
Extraction of multiple values stored in an object is known as
@dfn{destructuring}. Using @code{pcase} patterns allows to perform
@dfn{destructuring binding}, which is similar to a local binding
(@pxref{Local Variables}), but gives values to multiple elements of
a variable by extracting those values from an object of compatible
structure.
The macros described in this section use @dfn{destructuring
patterns}, which are normal Pcase patterns used in a context where we
presume that the object does match the pattern, and we only want
to extract some subfields. For example:
The macros described in this section use @code{pcase} patterns to
perform destructuring binding. The condition of the object to be of
compatible structure means that the object must match the pattern,
because only then the object's subfields can be extracted. For
example:
@example
(pcase-let ((`(add ,x ,y) l))
(pcase-let ((`(add ,x ,y) my-list))
(message "Contains %S and %S" x y))
@end example
@noindent
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
if @code{l} is a list which has the right number of elements and has
@code{add} as its first element.
The precise behavior when the object does not actually match the
pattern is undefined, although the body will not be silently skipped:
either an error is signaled or the body is run with some of the
variables potentially bound to arbitrary values like @code{nil}.
to extract @code{x} and @code{y} from @code{my-list} without first
verifying if @code{my-list} is a list which has the right number of
elements and has @code{add} as its first element. The precise
behavior when the object does not actually match the pattern is
undefined, although the body will not be silently skipped: either an
error is signaled or the body is run with some of the variables
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{}
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{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
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
@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{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
matched against its corresponding @var{pattern} before passing to the
next element of @var{bindings}, so the variables introduced in each
binding are available in the @var{exp}s that follow it, additionally
to being available in @var{body}.
Unlike @code{pcase-let}, but similarly to @code{let*}, each @var{exp}
is matched against its corresponding @var{pattern} before processing
the next element of @var{bindings}, so the variable bindings
introduced in each one of the @var{bindings} are available in the
@var{exp}s of the @var{bindings} that follow it, additionally to
being available in @var{body}.
@end defmac
@findex dolist
@defmac pcase-dolist (pattern list) body@dots{}
This construct executes @var{body} once for each element of
@var{list}, in a context where the variables appearing in the the
destructuring pattern @var{pattern} are bound to the corresponding
values found in the element.
When @var{pattern} is a simple variable, this ends up being equivalent
to @code{dolist}.
Execute @var{body} once for each element of @var{list}, on each
iteration performing a destructuring binding of variables in
@var{pattern} to the values of the corresponding subfields of the
element of @var{list}. The bindings are performed as if by
@code{pcase-let}. When @var{pattern} is a simple variable, this ends
up being equivalent to @code{dolist} (@pxref{Iteration}).
@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.
@end defmac
@defmac seq-let arguments sequence body@dots{}
@anchor{seq-let}
@defmac seq-let var-sequence val-sequence body@dots{}
@cindex sequence destructuring
This macro binds the variables defined in @var{arguments} to the
elements of @var{sequence}. @var{arguments} can themselves include
sequences, allowing for nested destructuring.
This macro binds the variables defined in @var{var-sequence} to the
values that are the corresponding elements of @var{val-sequence}.
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
followed by a variable name to be bound to the rest of
@code{sequence}.
The @var{var-sequence} sequence can also include the @code{&rest}
marker followed by a variable name to be bound to the rest of
@var{val-sequence}.
@example
@group
@ -1081,6 +1084,9 @@ followed by a variable name to be bound to the rest of
@end group
@result{} [3 4]
@end example
The @code{pcase} patterns provide an alternative facility for
destructuring binding, see @ref{Destructuring with pcase Patterns}.
@end defmac
@defun seq-random-elt sequence

View file

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