From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.devel Subject: Re: The poor state of documentation of pcase like things. Date: Fri, 18 Dec 2015 10:55:21 +0200 Message-ID: <83d1u4xhja.fsf@gnu.org> References: <20151216202605.GA3752@acm.fritz.box> Reply-To: Eli Zaretskii NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1450428921 20547 80.91.229.3 (18 Dec 2015 08:55:21 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 18 Dec 2015 08:55:21 +0000 (UTC) Cc: acm@muc.de, emacs-devel@gnu.org, kaushal.modi@gmail.com To: John Wiegley Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Dec 18 09:55:15 2015 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1a9qok-0002Yw-Ax for ged-emacs-devel@m.gmane.org; Fri, 18 Dec 2015 09:55:14 +0100 Original-Received: from localhost ([::1]:59016 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a9qoj-0006He-II for ged-emacs-devel@m.gmane.org; Fri, 18 Dec 2015 03:55:13 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:48898) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a9qof-0006Ft-Gw for emacs-devel@gnu.org; Fri, 18 Dec 2015 03:55:10 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1a9qob-0005i3-02 for emacs-devel@gnu.org; Fri, 18 Dec 2015 03:55:09 -0500 Original-Received: from fencepost.gnu.org ([2001:4830:134:3::e]:52239) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a9qoa-0005hT-U5; Fri, 18 Dec 2015 03:55:04 -0500 Original-Received: from 84.94.185.246.cable.012.net.il ([84.94.185.246]:1716 helo=HOME-C4E4A596F7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.82) (envelope-from ) id 1a9qoV-0005Kp-77; Fri, 18 Dec 2015 03:55:04 -0500 In-reply-to: (message from John Wiegley on Thu, 17 Dec 2015 16:42:13 -0800) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:4830:134:3::e X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 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-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:196454 Archived-At: > From: John Wiegley > Date: Thu, 17 Dec 2015 16:42:13 -0800 > Cc: Alan Mackenzie , Emacs developers > > >>>>> Kaushal Modi writes: > > > I would welcome a short tutorial on how (and why) to use pcase. > > The following is a brief pcase tutorial. I welcome any edits and comments. Thanks, please find below a few questions of a naïve reader. > Also, I wonder if anyone would be willing to hammer this into a form better > suited to the Emacs Lisp manual. I could try, but only if I understand this enough to write about it, and if the description you posted is complete (is it?). It's hard to convert tutorials into a manual section otherwise. > # QPatterns and UPatterns > > To master `pcase', there are two types of patterns you must know: UPatterns > and QPatterns. UPatterns are the "logical" aspect of pattern matching, where > we describe the kind of data we'd like to match against, and other special > actions to take when it matches; and QPatterns are the "literal" aspect, > stating the exact form of a particular match. What do "Q" and "U" stand for? "Quoted" and "Unquoted", something else? When introducing terminology that is not English words, you need to help the reader form a mental model by connecting terms to words. > The only special QPattern is the anti-quoting pattern, `,foo` But the example doesn't use `,foo`, it uses just ,foo. I guess `..` here is some markdown-style "quoting", unrelated to the Lisp backticks? > (pcase value > (`(1 2 ,(or `3 `4)) > (message "Matched either the list (1 2 3) or (1 2 4)"))) Do 3 and 4 really have to be quoted here? Why? > When performing a match, if a symbol occurs within a UPattern, it binds > whatever was found at that position to a local symbol of the same name. "Local symbol" here meaning what? an un-interned symbol or a local variable by that name? > (pcase value > (`(1 2 ,foo 3) > (message "Matched 1, 2, something now bound to foo, and 3")) > (foo > (message "Match anything at all, and bind it to foo!")) > (`(,the-car . ,the-cdr)) > (message "Match any cons cell, binding the car and cdr locally")) So to bind something to 'foo' you just use "foo", but to bind something to 'the-car' and 'the-cdr' you need to use ",the-car" and ",the-cdr"? Why the inconsistency? > The reason for doing this is two-fold: Either to refer to a previous match > later in the pattern (where it is compared using `eq'), or to make use of a > matched value within the related code block: > > (pcase value > (`(1 2 ,foo ,foo 3) > (message "Matched (1 2 %s %s 3)" foo))) ??? Is "foo" here bound to 2 different values? And how come the format has 2 %s, but only one variable, foo, to provide values? > We can express boolean logic within a pattern match using the `or` and `and` > Patterns: > > (pcase value > (`(1 2 ,(or 3 4) > ,(and (pred stringp) > (pred (string> "aaa")) > (pred (lambda (x) (> (length x) 10))))) > (message "Matched 1, 2, 3 or 4, and a long string " > "that is lexically greater than 'aaa'"))) Why did you use 'lambda' for the 3rd predicate, but not for the 2nd? Is it just a way to show off use of 'lambda', or is there some significant difference between these 2 use cases that requires a 'lambda' in the latter case? More generally, when is 'lambda' required in a predicate like these ones? > (pcase value > (`(1 2 ,foo ,(guard (and (not (numberp foo)) (/= foo 10))) > (message "Matched 1, 2, anything, and then anything again, " > "but only if the first anything wasn't the number 10")))) How is using 'guard' here different from using a predicate? > Note that in this example, the guard occurs at a match position, so even > though the guard doesn't refer to what is being matched, if it passes, then > whatever occurs at that position (the fourth element of the list), would be an > unnamed successful matched. What is the significance of an "unnamed successful matched"? > This is rather bad form, so we can be more > explicit about the logic here: > > (pcase value > (`(1 2 ,(and foo (guard (and (not (numberp foo)) (/= foo 10)))) _) > (message "Matched 1, 2, anything, and then anything again, " > "but only if the first anything wasn't the number 10")))) > > > This means the same, but associates the guard with the value it tests, and > makes it clear that we don't care what the fourth element is, only that it > exists. Again, how is this different from using a 'pred'? > > ## Pattern let bindings > > Within a pattern we can match sub-patterns, using a special form of let that > has a meaning specific to `pcase': > > (pcase value > (`(1 2 ,(and foo (let 3 foo))) > (message "A weird way of matching (1 2 3)"))) > > This example is a bit contrived, but it allows us to build up complex guard > patterns that might match against values captured elsewhere in the surrounding > code: > > (pcase value1 > (`(1 2 ,foo) > (pcase value2 > (`(1 2 ,(and (let (or 3 4) foo) bar)) > (message "A nested pcase depends on the results of the first"))))) > > Here the third value of `value2' -- which must be a list of exactly three > elements, starting with 1 and 2 -- is being bound to the local variable `bar', > but only if foo was a 3 or 4. Why do you need the 'let' here? Binding bar to the 3rd element can be expressed without a 'let', I think. And why is 'and' needed here? > That's all there is to know about `pcase'! The other two utilities you might > like to use are `pcase-let` and `pcase-let*`, which do similar things to their > UPattern counter-part `let', but as regular Lisp forms: > > (pcase-let ((`(1 2 ,foo) value1) > (`(3 4 ,bar) value2)) > (message "value1 is a list of (1 2 %s); value2 ends with %s" > foo bar)) Isn't it true that pcase-let is just a short-hand for a pcase that assigns values according to patterns, and has nil as the default value? If that's true, I think it explains better what pcase-let does, especially when backed up by an example of a pcase and the equivalent pcase-let. Looking at the ELisp manual's node "Pattern matching case statement", it sounds like everything you've described is already covered there, so perhaps what we need is more examples? Thanks.