From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Axel Forsman Newsgroups: gmane.emacs.devel Subject: Re: combining cond and let, to replace pcase. Date: Sun, 19 Nov 2023 16:08:08 +0000 (UTC) Message-ID: <87v89xbuah.fsf@axelf.se> References: Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="37249"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Spencer Baugh , emacs-devel@gnu.org To: rms@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Nov 19 17:08:56 2023 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r4kLv-0009UD-4J for ged-emacs-devel@m.gmane-mx.org; Sun, 19 Nov 2023 17:08:55 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r4kLI-0005AJ-Vr; Sun, 19 Nov 2023 11:08:17 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r4kLH-00059j-6Y for emacs-devel@gnu.org; Sun, 19 Nov 2023 11:08:15 -0500 Original-Received: from wrqvffvh.outbound-mail.sendgrid.net ([149.72.255.128]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1r4kLC-0005UN-Gj for emacs-devel@gnu.org; Sun, 19 Nov 2023 11:08:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axelf.se; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: content-transfer-encoding:cc:content-type:from:subject:to; s=s1; bh=i8Es8/FXYIOU5JUhG+Sxcd/9q2nl66IDXNvNlXA4BWw=; b=hy5e5BZLM73Ug2det0NUOv6Te5oPblTqcTO78RDNy4fAR7ASAf+S/F3hswgjVL6cPiVF WUmXXpC+pLD6OOxxTWNKnWtzdB7aSKCz5RJympVJ2ANC1wpYUkmgmGhLNepjAwVDtRrwR0 EzASIVDzKja1NyY0JL5uWDew9E7FP3PmPiu0QaO8YmYUpsrbTKE7U9ymdn5XXVpzaFGS0E Vd48vSnlTXJntg8lv6jry4VDiOB71vmM7ijyxg5bG5+ibhJdpEheiY6lWkSMgU9TxCkfQf gqZhn8ZPDGYAhftMyoid+njRkAwo6wYnxyf+/1sjG/gsv+bwdFWjcAzxG7vlO1Ew== Original-Received: by filterdrecv-5bbdbb56cd-52lf9 with SMTP id filterdrecv-5bbdbb56cd-52lf9-1-655A32E8-36 2023-11-19 16:08:08.463425699 +0000 UTC m=+2842094.283415488 Original-Received: from localhost (unknown) by geopod-ismtpd-5 (SG) with ESMTP id qblCEZMUSk609XrsnL8rLA Sun, 19 Nov 2023 16:08:07.980 +0000 (UTC) In-Reply-To: X-SG-EID: =?us-ascii?Q?a9jmprsm98cnqgHsU2O6rQhtHh4uQUltDI0sfxLQLLW0ScObgxI6amEU2a6U78?= =?us-ascii?Q?W+y=2F8zpDNbPSeC5UY+tl3hUPMpHp0YKuILPYKnC?= =?us-ascii?Q?n+eim87qNvtBcumckc1VRzsqo8L8woNEa5uM08u?= =?us-ascii?Q?+9RLQ8dwlQk=2F0i65awHI6Sv1=2FF4WkjH1wRCf0vR?= =?us-ascii?Q?xPgYk4sRXUKFDsNzo9zL6dFCwUChxTtuS78vzuV?= =?us-ascii?Q?wlBU=2FMNBv0U9ZvTEZwxwSxajuXSOE27ZrtcT3A?= X-Entity-ID: kO1dOy+IUnMwDrvHlPpg/w== Received-SPF: pass client-ip=149.72.255.128; envelope-from=bounces+28258838-fae1-emacs-devel=gnu.org@em3403.axelf.se; helo=wrqvffvh.outbound-mail.sendgrid.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 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-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:312999 Archived-At: Richard Stallman writes: > > I've thought before that it would be nice to have a cond-let construc= t, > > like if-let and when-let. > > Here's an example to show what I have come up with along these lines: > > (cond* (:bind (x foobar) y z (foo 5) a) ;; variables to bind, as in let > ;; I'm also thinking of using nil instead of :bind. > > ;; t as condition means run this clause unconditionally > ;; then continue with next clause. > (t do-this-unconditionally-and-dont-stop...) > > ;; Tests with a new function `match' which I'm going to work on ne= xt. > ((match x 'foo) ...) > > ;; t in the last clause means the same as in previous clauses, > ;; but you can think of it as being the same as in `cond'. > (t do-this-as-last-resort) > ) > > Rhe idea is that conf* does part of pcase's added functionality, and > `match' will do the rest. But it is not necessary to cram _all_ the > additional matching functionality (to compare to pcase) into a single > new function.=20 > > We could have more than one new function, eacn for its own kind of > pattern matching. > > Some of them could do destructuring as well as matching. pcase is not concerned with your proposed :bind and t keywords. For a discussion about pcase being too "large", it seems weird to suggest an alternative that does even more. What am I missing? Also, the various `match' constructs would have to be part of the conf* macro as destructuring needs to bind variables, so I fail to see how this would be an improvement over the status quo? I may be misinterpreting what you are proposing here, and in that case I apologize, but in general should one not try to understand the thing they are attempting to replace, or else likely make the same mistakes? > I hoipe that using a few constructs to divide up the job will avoid > the kludginess of pcase's bells-and-whistles-for-everything approach, > resulting in something equally convenient but made of simple components. I will preface this by saying that I like pcase, I think it is one of the better-written Emacs Lisp packages. History has shown that declarative pattern matching =E0 la ML is a good concept, with languages on the "other side of the pond" such as Java; Python; C++; JavaScript; and C#, all eventually adopting it. Any discussion about the purported complexity of pcase should start with delineating the essentials of pcase, (something I do not think this mailing thread has done a good job of), which is that the pcase syntax for destructuring a value should mirror the syntax for constructing that same value. E.g. `(if ,condition ,consequent ,alternative) constructs a list if condition, consequent, and alternative are variables currently bound, and is also a pcase pattern for deconstructing that same list. IMO that is perfectly simple. Does the addition of other pcase pattern-forms such as pred/app/guard/and/or complicate things too much? I would say maybe; it is certainly possible to abuse them. On the other hand, it is very useful to match against an integer in some range, nested withing a list, e.g. (pcase x (`(integer ,(and (pred (lambda (i) (< 0 i 5))) i)) (print i)) (`(integer ,i) (do-something-else i)) ...) >From what I have seen from languages that do not have special syntax for matching integers in ranges, this would usually be handled by guard expressions as a second step after matching is done, e.g. (pcase x (`(integer ,i) :when (< 0 i 5) (print i)) (`(integer ,i) (do-something-else i)) ...) Something like that would work to keep the patterns simpler. Without pred/app/guard/and/or one could think of getting rid of the messy backquote/comma syntax, for something cleaner based just on lists, e.g. (pcase x (('integer i) (print i)) (('if condition consequent alternative) (message "if")) ...) however that would not good for a couple of reasons: 1. The syntax for constructing lists is no longer the same as for destructuring. 2. It would leave little room for incorporating syntax for destructuring cl-struct:s, etc. pcase has the (cl-struct TYPE &rest FIELDS) form for this purpose, which is what it is, but at least I think it is good that it exists. This is all to say that I disagree with your claim that pcase has a bells-and-whistles-for-everything approach. Rather it is maximally compositional and based on the easy-to-learn and neat duality of constructing/destructuring. I also consider it a mistake to introduce forms such as > ;; t as condition means run this clause unconditionally > ;; then continue with next clause. > (t do-this-unconditionally-and-dont-stop...) with non-descriptive names such as nil/t, that introduce side-effects in the middle of matching something. Pattern matching is great because it is declarative and makes it possible to communicate intent, rather than concerning ourselves with what combination of car/cdr/equal/let/if is needed to achieve what we want.