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.devel Subject: Re: pcase generates an unprintable expansion for a form in test erc--restore-initialize-priors Date: Thu, 30 May 2024 19:43:01 -0400 Message-ID: References: <87sey3awa5.fsf@web.de> <87mso84ogy.fsf@web.de> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="23925"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Michael Heerdegen via "Emacs development discussions." To: Michael Heerdegen Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Fri May 31 01:44:03 2024 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 1sCpRC-0005yx-D4 for ged-emacs-devel@m.gmane-mx.org; Fri, 31 May 2024 01:44:02 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sCpQM-0008Sr-UY; Thu, 30 May 2024 19:43:10 -0400 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 1sCpQK-0008SP-Af for emacs-devel@gnu.org; Thu, 30 May 2024 19:43:08 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sCpQH-0004al-R1 for emacs-devel@gnu.org; Thu, 30 May 2024 19:43:08 -0400 Original-Received: from pmg3.iro.umontreal.ca (localhost [127.0.0.1]) by pmg3.iro.umontreal.ca (Proxmox) with ESMTP id 0D5834449FA; Thu, 30 May 2024 19:43:04 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1717112581; bh=OVdN1Wv35/Z2UijDR9Qfmgru4NhjiO4bLlsAn40uDbc=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=JfzhyyPL5Sm8Jhe9ISx1qsk03PZk/pDpLbgvvaFr4VU6M+MUaBVYVQMigu5EfyWmT p6kJyZxa2kkNuggBFqSpM7idyH+JGJ/2F4deFDDtTCrqhSw1hUdsO9X0Sp/7ghZ9fq 09LNHSzTca03AkOf7O3sLV2ko3xOzM+zgyRJroxWqtjLQPGzH6PuLYiL0toFuRGXBi LnnMYIxc+EyBrqI//fAP4NEeRRvGI1IQ8lluKuw/MfkRFvmK5k1c4loU86+wWYWYbo oLYOy/bHtKRgOT7lOk1nzSG7oxrQ/WUaDs/uflJup2UufAMWlN3RQ6MBu7HTkAEBwI l4+iy3RfgP1vg== Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg3.iro.umontreal.ca (Proxmox) with ESMTP id A5EE74449F7; Thu, 30 May 2024 19:43:01 -0400 (EDT) Original-Received: from lechazo (lechon.iro.umontreal.ca [132.204.27.242]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id 8E4F71202C7; Thu, 30 May 2024 19:43:01 -0400 (EDT) In-Reply-To: <87mso84ogy.fsf@web.de> (Michael Heerdegen's message of "Wed, 29 May 2024 17:39:09 +0200") Received-SPF: pass client-ip=132.204.25.50; envelope-from=monnier@iro.umontreal.ca; helo=mailscanner.iro.umontreal.ca X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham 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:319762 Archived-At: > I must admit however - I still wonder: Code and matched structures will > be proper short-length lists most of the time - would it be possible and > make sense to handle all list elements at the same recursion level > instead of doing O(length) recursive descents? I think if you look at the bytecode you'll see it uses a lot less stack space, so the problem is not as serious as it seems. Apart from that, for the specific case of matching against just one pattern, we could do better. As mentioned earlier, that's what `match*` does. In contrast `pcase.el` is designed to solve the more general case of pattern matching against several patterns at the same time with the goal of avoiding repeating the same operation across the various patterns. See below the code that `match*` generates. As you can see, it's much less nested (but it does a lot of redundant computations even for this one pattern). [ Note also that the code generated by `pcase.el` (without my patch), while much more deeply nested, is only about twice the size of the code generated by `match*`. With my patch, it is almost the same size (about 10% larger still). I measured the size via `prin1-to-string` and get about the same relative results when looking at interpreted code and the byte-compiled code. So, I'm quite happy with `pcase.el` performance for this case. ] Stefan ELISP> (macroexpand '(cond* ((match* `(let* ((,p (or erc--server-reconnecting erc--target-priors)) (,q (and ,p (alist-get 'erc-my-mode ,p)))) (unless (local-variable-if-set-p 'erc-my-mode) (error "Not a local minor mode var: %s" 'erc-my-mode)) (setq foo (if ,q (alist-get 'foo ,p) (ignore 1 2 3)) bar (if ,q (alist-get 'bar ,p) #'spam) baz (if ,q (alist-get 'baz ,p) nil))) EXP) RES))) (let ((d2 EXP)) (if (and (consp d2) (eq 'let* (nth 0 d2)) (consp (nthcdr 1 d2)) (and (consp (nth 1 d2)) (and (consp (nth 0 (nth 1 d2))) (equal '((or erc--server-reconnecting erc--target-priors)) (cdr (nth 0 (nth 1 d2))))) (consp (nthcdr 1 (nth 1 d2))) (and (consp (nth 1 (nth 1 d2))) (consp (nthcdr 1 (nth 1 (nth 1 d2)))) (and (consp (nth 1 (nth 1 (nth 1 d2)))) (eq 'and (nth 0 (nth 1 (nth 1 (nth 1 d2))))) (consp (nthcdr 1 (nth 1 (nth 1 (nth 1 d2))))) (equal (car (nth 0 (nth 1 d2))) (nth 1 (nth 1 (nth 1 (nth 1 d2))))) (consp (nthcdr 2 (nth 1 (nth 1 (nth 1 d2))))) (and (consp (nth 2 (nth 1 (nth 1 (nth 1 d2))))) (eq 'alist-get (nth 0 (nth 2 (nth 1 (nth 1 (nth 1 d2)))))) (consp (nthcdr 1 (nth 2 (nth 1 (nth 1 (nth 1 d2)))))) (equal ''erc-my-mode (nth 1 (nth 2 (nth 1 (nth 1 (nth 1 d2)))))) (consp (nthcdr 2 (nth 2 (nth 1 (nth 1 (nth 1 d2)))))) (equal (car (nth 0 (nth 1 d2))) (nth 2 (nth 2 (nth 1 (nth 1 (nth 1 d2)))))) (null (nthcdr 3 (nth 2 (nth 1 (nth 1 (nth 1 d2))))))) (null (nthcdr 3 (nth 1 (nth 1 (nth 1 d2)))))) (null (nthcdr 2 (nth 1 (nth 1 d2))))) (null (nthcdr 2 (nth 1 d2)))) (consp (nthcdr 2 d2)) (equal '(unless (local-variable-if-set-p 'erc-my-mode) (error "Not a local minor mode var: %s" 'erc-my-mode)) (nth 2 d2)) (consp (nthcdr 3 d2)) (and (consp (nth 3 d2)) (eq 'setq (nth 0 (nth 3 d2))) (consp (nthcdr 1 (nth 3 d2))) (eq 'foo (nth 1 (nth 3 d2))) (consp (nthcdr 2 (nth 3 d2))) (and (consp (nth 2 (nth 3 d2))) (eq 'if (car (nth 2 (nth 3 d2)))) (and (consp (cdr (nth 2 (nth 3 d2)))) (equal (nth 0 (nth 1 (nth 1 d2))) (car (cdr (nth 2 (nth 3 d2))))) (and (consp (cdr (cdr (nth 2 (nth 3 d2))))) (and (consp (car (cdr (cdr (nth 2 (nth 3 d2)))))) (eq 'alist-get (nth 0 (car (cdr (cdr (nth 2 (nth 3 d2))))))) (consp (nthcdr 1 (car (cdr (cdr (nth 2 (nth 3 d2))))))) (equal ''foo (nth 1 (car (cdr (cdr (nth 2 (nth 3 d2))))))) (consp (nthcdr 2 (car (cdr (cdr (nth 2 (nth 3 d2))))))) (equal (car (nth 0 (nth 1 d2))) (nth 2 (car (cdr (cdr (nth 2 (nth 3 d2))))))) (null (nthcdr 3 (car (cdr (cdr (nth 2 (nth 3 d2)))))))) (equal '((ignore 1 2 3)) (cdr (cdr (cdr (nth 2 (nth 3 d2))))))))) (consp (nthcdr 3 (nth 3 d2))) (eq 'bar (nth 3 (nth 3 d2))) (consp (nthcdr 4 (nth 3 d2))) (and (consp (nth 4 (nth 3 d2))) (eq 'if (car (nth 4 (nth 3 d2)))) (and (consp (cdr (nth 4 (nth 3 d2)))) (equal (nth 0 (nth 1 (nth 1 d2))) (car (cdr (nth 4 (nth 3 d2))))) (and (consp (cdr (cdr (nth 4 (nth 3 d2))))) (and (consp (car (cdr (cdr (nth 4 (nth 3 d2)))))) (eq 'alist-get (nth 0 (car (cdr (cdr (nth 4 (nth 3 d2))))))) (consp (nthcdr 1 (car (cdr (cdr (nth 4 (nth 3 d2))))))) (equal ''bar (nth 1 (car (cdr (cdr (nth 4 (nth 3 d2))))))) (consp (nthcdr 2 (car (cdr (cdr (nth 4 (nth 3 d2))))))) (equal (car (nth 0 (nth 1 d2))) (nth 2 (car (cdr (cdr (nth 4 (nth 3 d2))))))) (null (nthcdr 3 (car (cdr (cdr (nth 4 (nth 3 d2)))))))) (equal '(#'spam) (cdr (cdr (cdr (nth 4 (nth 3 d2))))))))) (consp (nthcdr 5 (nth 3 d2))) (eq 'baz (nth 5 (nth 3 d2))) (consp (nthcdr 6 (nth 3 d2))) (and (consp (nth 6 (nth 3 d2))) (eq 'if (car (nth 6 (nth 3 d2)))) (and (consp (cdr (nth 6 (nth 3 d2)))) (equal (nth 0 (nth 1 (nth 1 d2))) (car (cdr (nth 6 (nth 3 d2))))) (and (consp (cdr (cdr (nth 6 (nth 3 d2))))) (and (consp (car (cdr (cdr (nth 6 (nth 3 d2)))))) (eq 'alist-get (nth 0 (car (cdr (cdr (nth 6 (nth 3 d2))))))) (consp (nthcdr 1 (car (cdr (cdr (nth 6 (nth 3 d2))))))) (equal ''baz (nth 1 (car (cdr (cdr (nth 6 (nth 3 d2))))))) (consp (nthcdr 2 (car (cdr (cdr (nth 6 (nth 3 d2))))))) (equal (car (nth 0 (nth 1 d2))) (nth 2 (car (cdr (cdr (nth 6 (nth 3 d2))))))) (null (nthcdr 3 (car (cdr (cdr (nth 6 (nth 3 d2)))))))) (equal '(nil) (cdr (cdr (cdr (nth 6 (nth 3 d2))))))))) (null (nthcdr 7 (nth 3 d2)))) (null (nthcdr 4 d2))) (let* ((q (nth 0 (nth 1 (nth 1 d2)))) (p (car (nth 0 (nth 1 d2))))) RES) nil)) ELISP>