From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: Replace trivial pcase occurrences in the Emacs sources Date: Tue, 30 Oct 2018 16:44:01 -0400 Message-ID: References: <83tvlcsnee.fsf@gnu.org> <86mur137n8.fsf@gmail.com> <20181029130132.GB4195@ACM> <20181029134722.GC4195@ACM> <87lg6gifnb.fsf@web.de> <87muqwxs7m.fsf@ericabrahamsen.net> <83h8h3jlyd.fsf@gnu.org> <83efc7jjm2.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1540932135 20456 195.159.176.226 (30 Oct 2018 20:42:15 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 30 Oct 2018 20:42:15 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) Cc: emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Oct 30 21:42:11 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gHaq2-0005Cp-2N for ged-emacs-devel@m.gmane.org; Tue, 30 Oct 2018 21:42:10 +0100 Original-Received: from localhost ([::1]:55438 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gHas8-0006SS-7Y for ged-emacs-devel@m.gmane.org; Tue, 30 Oct 2018 16:44:20 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:33258) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gHary-0006SM-Kk for emacs-devel@gnu.org; Tue, 30 Oct 2018 16:44:11 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gHaru-0004PF-QH for emacs-devel@gnu.org; Tue, 30 Oct 2018 16:44:10 -0400 Original-Received: from chene.dit.umontreal.ca ([132.204.246.20]:39414) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gHars-0004OY-W2; Tue, 30 Oct 2018 16:44:05 -0400 Original-Received: from pastel.home (lechon.iro.umontreal.ca [132.204.27.242]) by chene.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id w9UKi2mg013621; Tue, 30 Oct 2018 16:44:02 -0400 Original-Received: by pastel.home (Postfix, from userid 20848) id D40D06A40C; Tue, 30 Oct 2018 16:44:01 -0400 (EDT) In-Reply-To: <83efc7jjm2.fsf@gnu.org> (Eli Zaretskii's message of "Tue, 30 Oct 2018 21:54:29 +0200") X-NAI-Spam-Flag: NO X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0 X-NAI-Spam-Rules: 2 Rules triggered EDT_SA_DN_PASS=0, RV6407=0 X-NAI-Spam-Version: 2.3.0.9418 : core <6407> : inlines <6948> : streams <1802841> : uri <2741258> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 132.204.246.20 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:230854 Archived-At: > 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 +@node Destructuring patterns +@subsection Destructuring Patterns +@cindex 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: + +@example + (pcase l + (`(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 +@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. + +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: + +@example + (pcase-let ((`(add ,x ,y) l)) + (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}. + +@defmac pcase-let bindings body@dots{} +Bind variables according to @var{bindings} and then eval @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. + +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}. +@end defmac + +@defmac pcase-let* bindings body@dots{} +Bind variables according to @var{bindings} and then eval @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. + +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}. +@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}. +@end defmac + + @node Iteration @section Iteration @cindex iteration