From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Barry Fishman Newsgroups: gmane.emacs.devel Subject: Re: Instead of pcase Date: Sun, 19 Nov 2023 16:15:25 -0500 Message-ID: <7nv89x5tsi.fsf@ecube.ecubist.org> References: <87fs169mjj.fsf@posteo.net> <093f11a1-57c2-5e56-d39b-26fef1c67cbb@gutov.dev> <25942.25061.217864.329049@retriever.mtv.corp.google.com> <87zfzdcz6z.fsf@posteo.net> <87zfza2aq2.fsf@web.de> <7nmsv9zq6u.fsf@ecube.ecubist.org> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19556"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) To: emacs-devel@gnu.org Cancel-Lock: sha1:KzX3fztGNV3XvSy4JiiJrad02F0= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Nov 19 22:16:35 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 1r4p9e-0004yt-GU for ged-emacs-devel@m.gmane-mx.org; Sun, 19 Nov 2023 22:16:34 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r4p8m-0004lf-Jh; Sun, 19 Nov 2023 16:15:40 -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 1r4p8l-0004lV-NI for emacs-devel@gnu.org; Sun, 19 Nov 2023 16:15:39 -0500 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r4p8h-0002nc-8k for emacs-devel@gnu.org; Sun, 19 Nov 2023 16:15:39 -0500 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1r4p8e-0003oJ-WC for emacs-devel@gnu.org; Sun, 19 Nov 2023 22:15:33 +0100 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.25, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no 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:313020 Archived-At: On 2023-11-19 19:59:42 +02, Dmitry Gutov wrote: > On 19/11/2023 18:02, Barry Fishman wrote: >> On 2023-11-19 13:23:17 +01, Michael Heerdegen wrote: >>> So, the advantage would be more of a psychological kind: you have normal >>> Lisp function calls, but structurally you have the same thing, and you >>> have to remember exactly the same set of details. The complexity comes >>> from the task, not from the implementation. >> I submit that the opposite is true, the complexity is in its >> implementation, not the task. >> In languages like Haskell this is expressed in a very simple way, so >> the >> task is not in itself hard to understand. > > Haskell is notable for using the same (or similar) syntax for > destructuring as it uses for constructing expressions. > > pcase actually follows that practice with backquotes and commas. Really? I thought back-quoting was used (as an alternative way) to construct nested lists, to express more simply the piecing together and concatenating nested list pieces, particularly in macroes, and its expansion at compile time is fairly obvious. I guess what pcase is trying to do is the similar, but it is expressing something that, to me, seem far more complex to use. Its also mixing "destructuring" and "guard"s, all in one "super" domain specific language. Like loop, it can be powerful, but intimidating to people that don't use it a lot. But its usefulness to those that know it, encourages its use in the code base. But exiting Lisp destructuring via destructuring-bind and lambda arguments, don't use backquoting. One thing I did change was to reverse the defmethod style of (variable type) to (type variable) to try to simplify recursion in the typeproto syntax. > And in both matching and destructuring are done in the same expression > (the presence of the latter is determined by whether a pattern > contains variable bindindgs). > >> If x is a list with its first element a string "foo" and the second an >> integer, remove it from x and add the second element to total: >> (proto-case x >> ((list* (string name) (integer count) (t rest)) >> (string-equal name "foo") >> (set! total (+ total count)) >> (set! x rest))) >> This is just one of many other ways one could setup a matching >> expression in elisp, the best is a balance between implementation >> efficiency and readability. > > And this divorces matching from destructuring. I suggest you try > rewriting one of the more complex pcase usages into this syntax and > see what people think of the result. You want me to guess what you have in mind? I have no idea. I'll take the example pcase code from the Emacs manual: (pcase (get-return-code x) ;; string ((and (pred stringp) msg) (message "%s" msg)) ;; symbol ('success (message "Done!")) ('would-block (message "Sorry, can't do it now")) ('read-only (message "The shmliblick is read-only")) ('access-denied (message "You do not have the needed rights")) ;; default (code (message "Unknown return code %S" code))) This is a simple use case, so its hard to use to draw any conclusions. This is mostly value handling for a known type, which is to me a different problem than destructuring, and be handled better by a generalized value case structure. But still: (let ((msglist '((success . "Done!") (would-block . "Sorry, can't do it now") (read-only . "The shmliblick is read-only") (access-denied . "You do not have the needed rights")))) (proto-case (get-return-code x) ((string msg) t (message "%s" msg)) ((symbol sym) t (let ((pair (assq sym msglist))) (if pair (message (cdr pair)) (message "Unknown return symbol %S" sym)))) ((t code) t (message "Unknown return type %S" code)))) In this situation pcase situation is a slightly better, to my sensibility's. [Now that pcase is written] One could also define a value oriented traditional style case: (vcase (x typecmp default) ((value expression ...) ...)) Which tests x using (funcall typecmp x value), and returns default if there is no match. And avoid the proto-case all together: (let ((code (get-return-code))) (cond ((stringp code) (message "%s" msg)) ((symbolp code) (or (vcase (sym eq nil) ('success (message "Done!")) ('would-block (message "Sorry, can't do it now")) ('read-only (message "The shmliblick is read-only")) ('access-denied (message "You do not have the needed rights"))) (message "Unknown return code %S" sym))) (t (message "Unknown return type %S" code)))) -- Barry Fishman