From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.bugs Subject: bug#43100: 28.0.50; pcase not binding variables conditionally Date: Sat, 05 Sep 2020 12:52:14 -0400 Message-ID: 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="3870"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Cc: Philipp Stephani , 43100@debbugs.gnu.org To: Pip Cet Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Sep 05 18:53:10 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1kEbR7-0000sD-Hh for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 05 Sep 2020 18:53:09 +0200 Original-Received: from localhost ([::1]:56734 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kEbR6-00037s-G7 for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 05 Sep 2020 12:53:08 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:56122) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kEbR0-00037k-HY for bug-gnu-emacs@gnu.org; Sat, 05 Sep 2020 12:53:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:60663) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kEbR0-0004oE-8B for bug-gnu-emacs@gnu.org; Sat, 05 Sep 2020 12:53:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1kEbR0-0006Z6-73 for bug-gnu-emacs@gnu.org; Sat, 05 Sep 2020 12:53:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 05 Sep 2020 16:53:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 43100 X-GNU-PR-Package: emacs Original-Received: via spool by 43100-submit@debbugs.gnu.org id=B43100.159932475725205 (code B ref 43100); Sat, 05 Sep 2020 16:53:02 +0000 Original-Received: (at 43100) by debbugs.gnu.org; 5 Sep 2020 16:52:37 +0000 Original-Received: from localhost ([127.0.0.1]:43976 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kEbQa-0006YS-VM for submit@debbugs.gnu.org; Sat, 05 Sep 2020 12:52:37 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]:16943) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kEbQY-0006YF-4f for 43100@debbugs.gnu.org; Sat, 05 Sep 2020 12:52:34 -0400 Original-Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id E7466809C7; Sat, 5 Sep 2020 12:52:27 -0400 (EDT) Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 26FFF8092B; Sat, 5 Sep 2020 12:52:21 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1599324741; bh=qImv46PdyQzxzLkRgwuRfsK5i0oKZ8r50lJWHRRur5M=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From; b=iBfa7Omt3yxQv9xfmPxzLmjCL6ii4BOYqBWeR7hmDEp3QKFbvvpaXT6O3dfhpdkxa khXz8A3zBqWsQzHvEGajqBKTFnA7fATXI3kgklU57+zn2y2/MPxxgurIOG766DeiVG cm4dBXviZASk2dtxHJbqLT2zD0isBdnp3tjprTX/46TCh2VYOFLnQHGdGLSoKuV2xS ztigk7j8SundEO9yM7eyzKwm1JJmAphjny4xQmZPBlnZq4iXA0FxaVnVedCE4tIjkl PDcqtpTWQReVNemwWNapulED8iYcoNZAYZfEyId5QnUVxllq2NxuEO1XYCkHnh13Ax XScq2YIMqDlWA== Original-Received: from alfajor (unknown [45.72.232.131]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id E77E9120604; Sat, 5 Sep 2020 12:52:20 -0400 (EDT) In-Reply-To: (Pip Cet's message of "Sat, 5 Sep 2020 14:36:50 +0000") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:187281 Archived-At: >> >> I just want the complexity to be predictable without having to guess >> >> which optimization will be applicable. >> > So it's better to have a predictably-bad `append' rather than a >> > sometimes-bad one? >> In my book, yes. > That's a very unusual book! I wouldn't know, it's the only one I have. > This isn't real-time programming or crypto, so I fail to see the > damage "faster is better" might cause here. Because the problem goes in the other direction: the programmer gets used to seeing it work fast on some uses and then assumes it's always so, and then gets bitten on other uses. I think a good API should avoid such surprises. [ This said, I no doubt introduced several APIs which don't obey this rule. But then I plead not guilty because of temporary insanity. ] >> > But how does that affect ,@? We could make that predictably bad, too! >> I think the expectation (coming from the use of ,@ in non-patterns) >> would be that it is fairly cheap, but yes, I guess it's an option. >> Could be coupled with a warning when ,@ can be replaced by an efficient >> `. ,`. > I don't think we should warn about that; we should simply do the best > we can do, and warn the user when that's surprisingly bad (i.e. when > we have to iterate over the list building sublists). It's important to try and make sure that warnings can be silenced by improving the code. When the coders really need the slow search, how would they silence the warning (other than `with-suppressed-warnings`, obviously)? In contrast if we warn when the ,@ can be replaced by `, .` then the warning can always be silenced without having to resort to `with-suppressed-warnings`. >> >> >> More specifically, I'd rather not choose a semantics that imposes >> >> >> duplicating the branch body, since we have no control over its siz= e and >> >> >> that can hence lead to potential code size explosion. >> >> > You're right, and it's a good thing that the duplication of the bra= nch >> >> > body is a fixable implementation detail rather than something impos= ed >> >> > by the semantics. >> >> It's only fixable if you disregard the "more or less" above. >> >> I find it to be a pretty bad wrinkle in the semantics. >> > So setq the outer binding if it changed? >> Oh, yuck! That'd be adding injury to insult. > Would work, though! And would result in hideous semantics in corner cases. > What I meant was using SYMBOL as short-hand for (pred (equal SYMBOL)) > when it's not in a white-list of symbols to be bound instead of > compared. That was the intention of my example. Ah, sorry, I completely misunderstood ;-) There's also a case to be made for SYMBOL to be an accepted short form for `(pred SYMBOL)` in some cases. I don't think using whitelists/blacklists to decide how to treat a given SYMBOL pattern will scale (nor be sufficiently clear for the casual reader), so I think we should aim for a slightly less concise syntax. Given the limits of the syn= tax accepted by the Elisp reader, we may have to resort to using (=3D EXP) as shorthand for (pred (equal EXP)) or =3DSYMBOL as shorthand for (pred (equal SYMBOL)) AFAIK There is currently no good hook in `pcase.el` to implement the latter without actually changing `pcase.el`. > I think dynamic patterns, as you use the term, should be possible They very much are possible, of course. E.g.: (defun pcase-match-p (PATTERN OBJECT) "Return non-nil if OBJECT matches PATTERN." (eval `(pcase ',OBJECT (,PATTERN t)) t)) and then use (pred (pcase-match-p EXP)) If you want to extract data from OBJECT, then you'll presumably want to define a `pcase-match` function which instead of a boolean returns a list of values (corresponding to the value of the variables that were bound in the PATTERN) and that will take more work than the above 3 lines, but should still be easy to do. > but punitively slow Yup. >> >> We have `help-function-arglist`, so it's not that hard. >> >> But it's not guaranteed to work. >> > Oh, thanks for pointing that out. It's not very good, though, is it? >> It's good enough for `C-h o`. > > C-h o says > > (+ &rest NUMBERS-OR-MARKERS) and (1+ NUMBER) Indeed and that info comes straight from `help-function-arglist`. > help-function-arglist says > > (&rest rest) and (arg1) I suggest you start with `C-h o help-function-arglist` ;-) >> >> I'm sorry, I don't understand what those sexps (and their =ABoptional" >> >> non-final parts=BB) have to do with pcase's handling of `or` patterns >> >> where the different branches don't bind the same set of variables. >> > Well, maybe I'm just missing an obvious way of doing it. >> Could be, but I have no idea what "it" is. > > Matching something like Emacs defuns, which may have a docstring or > not, I'd like to do > > `(defun ,symbol ,@(or `(,(and (pred stringp) docstring))) `()) . ,body) > > It seems wasteful to have two almost-identical patterns to match the > variants, and I'd like docstring to have a useful default value. Currently `pcase` should give nil as value to `docstring` if the above `or` matches via the second alternative, so at least the "useful default" part is already covered ;-) But yes, currently, you have to write it like `(defun ,symbol ,args . ,(or `(,(and (pred stringp) docstring) . ,body) body)) or if you want a more explicit default for `docstring`: `(defun ,symbol ,args . ,(or `(,(and (pred stringp) docstring) . ,body) (and (let docstring "") body))) In this particular case it's not too terrible, but it gets much worse if you have to add more optional stuff to it, like `declare` and `interactive` (the pattern's size is exponential in the number of optional elements). Your `append` handles it more elegantly in the source code (and less efficiently at run-time). In theory we could get our cake and eat it too, but that would involve adding something similar to a parsing algorithm and would likely require a significant amount of work. >> > And, again, performance of ` is unpredictable unless you know the >> > details of the optimization. Should we get rid of ` next? >> AFAIK performance is O(N) where N is the number of cons cells in the >> output (minus those cons-cells which are preserved as-is, I guess but >> that doesn't make much of a difference). > It means (,@l) is O(1), but (,@l 3) is O(N). Indeed. It's not as drastic as the O(1) of `. ,` vs O(N=B2) of `append`, but point taken. I think it's time you (pcase-defmacro pip-\` ...) and experiment with it. > By the way, I'm also quite confused by this comment: > > ;; - implement (not PAT). This might require a significant redesign. > > (pcase-defmacro not (pat) > `(app (lambda (expval) (not (pcase expval (,pat t)))) > (pred identity))) > > would work, wouldn't it? [ AKA (pcase-defmacro not (pat) `(pred (lambda (expval) (not (pcase expval (,pat t)))))) ] Yes, it works but it doesn't give me the efficiency and semantics that a "true" `not` pattern should give. If you look at Racket's `match` (from which I took a lot of inspiration in the Emacs-25 refresh of pcase), you'll see that their negation pattern is trivial to implement (it's basically just swapping the "things to do upon success" with the "things to do upon failure") but gives the right semantics and efficiency. E.g. `(not (not PAT))` behaves just like PAT (including variable bindings and such). Stefan