emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Replace trivial pcase occurrences in the Emacs sources


From: Stefan Monnier
Subject: Re: Replace trivial pcase occurrences in the Emacs sources
Date: Tue, 30 Oct 2018 16:44:01 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

> I think the best place of defining them is where we first describe
> them, i.e. in the section about pcase itself.

That's what I tried to do in the patch I had attached.

> No, I think "destructuring" is about right.  How about this text:
>
>   @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.

Fine by me.

>> > It would also help to tell what exactly makes a pattern a
>> > destructuring one.
>> As the paragraph says: it's the context in which it's used.
> I'm not sure I understand.  AFAIU, not every pattern described in
> "pcase Macro" can be a destructuring one.  Right?

A destructuring pattern can bind any number of variables, so I don't see
why we should limit this number to be strictly positive.

A pattern like 'Emacs will not be very useful on its own in pcase-let,
admittedly, but it's perfectly valid to use it (it will just do the same
as _, which is often convenient to use when you don't care about the
value).  And of course, it can even be useful to use it within a larger
pattern, e.g.

    (pcase-let (((or (and 'Emacs (let x 'a))
                     `(,x . ,_))
                 'Emacs))
      x)

will return `a` whereas

    (pcase-let (((or (and 'Emacs (let x 'a))
                     `(,x . ,_))
                 'Typer))
      x)

will signal an error (because it's trying to destructure `Typer` according
to `(,x . ,_)).

> See above: not every pattern can be a destructuring one, AFAIU.

They all can be used as destructuring patterns.  Some are more often
useful than others.

> I find this too abstract in general, so I think it's better to be
> specific where we can.

So, but this is as specific as I can be.  Maybe you'd prefer something
less specific.  See new patch below,


        Stefan


diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 5be4b298b4..06c6622bf0 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -477,6 +477,7 @@ Pattern-Matching Conditional
 * 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.
+* Destructuring patterns:: Using pcase patterns to extract subfields.
 @end menu
 
 @node pcase Macro
@@ -497,6 +498,10 @@ pcase Macro
 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}.
+
 The rest of this subsection
 describes different forms of core patterns,
 presents some examples,
@@ -1168,6 +1173,90 @@ Backquote Patterns
 (evaluate '(sub 1 2) nil)                 @result{} error
 @end example
 
address@hidden Destructuring patterns
address@hidden Destructuring Patterns
address@hidden destructuring 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:
+
address@hidden
+  (pcase l
+    (`(add ,x ,y)  (message "Contains %S and %S" x y)))
address@hidden 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,
address@hidden will directly return @code{nil} without calling
address@hidden
+
address@hidden 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.
+
+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:
+
address@hidden
+  (pcase-let ((`(add ,x ,y) l))
+    (message "Contains %S and %S" x y))
address@hidden example
+
address@hidden
+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
address@hidden 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}.
+
address@hidden pcase-let bindings address@hidden
+Bind variables according to @var{bindings} and then eval @var{body}.
+
address@hidden is a list of bindings of the form @address@hidden(@var{pattern}
address@hidden)}}, where @var{exp} is an expression to evaluate and
address@hidden is a destructuring pattern.
+
+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}.
address@hidden defmac
+
address@hidden pcase-let* bindings address@hidden
+Bind variables according to @var{bindings} and then eval @var{body}.
+
address@hidden is a list of bindings of the form @code{(@var{pattern}
address@hidden)}, where @var{exp} is an expression to evaluate and
address@hidden is a destructuring pattern.
+
+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}.
address@hidden defmac
+
address@hidden dolist
address@hidden pcase-dolist (pattern list) address@hidden
+This construct executes @var{body} once for each element of
address@hidden, 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}.
address@hidden defmac
+
+
 @node Iteration
 @section Iteration
 @cindex iteration



reply via email to

[Prev in Thread] Current Thread [Next in Thread]