From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Thuna Newsgroups: gmane.emacs.bugs Subject: bug#72344: [PATCH] Add a version of cl-once-only which handles lists of forms Date: Sun, 04 Aug 2024 00:40:22 +0200 Message-ID: <871q35mdrd.fsf@gmail.com> References: <87y15l1aj8.fsf@gmail.com> <8734nsk72i.fsf@melete.silentflame.com> <87plqw0y9j.fsf@gmail.com> <87ikwi5neo.fsf@melete.silentflame.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="21954"; mail-complaints-to="usenet@ciao.gmane.io" Cc: 72344@debbugs.gnu.org To: Sean Whitton Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Aug 04 00:42:00 2024 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 1saNRo-0005Zy-BX for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 04 Aug 2024 00:42:00 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1saNRX-0007Yd-R3; Sat, 03 Aug 2024 18:41:43 -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 1saNRW-0007YT-Bx for bug-gnu-emacs@gnu.org; Sat, 03 Aug 2024 18:41:42 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1saNRW-0001Id-1V for bug-gnu-emacs@gnu.org; Sat, 03 Aug 2024 18:41:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:References:In-Reply-To:From:To:Subject; bh=5cQFhVV2qGc/Gj69EmlfFgi1sxacw89egnsjAo4mUcs=; b=Bkm9qLypWAGK/xbuOX0E1v5bZWvWBh7OfKsacTPQgPfYYQqJ3TQZcumovjj9gopXLqPG5Xuavf2+k67jcpoP1lnmz+q1Gv94u6L4lC88dosrwmTWGo4/7xZ0/kqxq150i5HCxPQ4ZflOmq9LPTJ2T9bbonnTF3DeVcrOhwHBCiLc+HGE8o7XNx6OLsb6HKomZQgZZg8ify5S6692drE1IQaZhsxxfozQBHhULHNHlEMB9xQ5F260lnTb4UmJIqZuJYwU1QKmBg5Enk6ST1rkZauCnDElCLGaiC46iyJdw9Jw5+QNLoSabZ6g0s8d7C/5z0BLzP86OmDT+S4jkj/V4Q==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1saNRq-0003Ge-6Q for bug-gnu-emacs@gnu.org; Sat, 03 Aug 2024 18:42:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Thuna Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 03 Aug 2024 22:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72344 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 72344-submit@debbugs.gnu.org id=B72344.172272491412526 (code B ref 72344); Sat, 03 Aug 2024 22:42:02 +0000 Original-Received: (at 72344) by debbugs.gnu.org; 3 Aug 2024 22:41:54 +0000 Original-Received: from localhost ([127.0.0.1]:54923 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1saNRi-0003Fx-2z for submit@debbugs.gnu.org; Sat, 03 Aug 2024 18:41:54 -0400 Original-Received: from mail-wm1-f51.google.com ([209.85.128.51]:56745) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1saNRg-0003FZ-Oq for 72344@debbugs.gnu.org; Sat, 03 Aug 2024 18:41:53 -0400 Original-Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-4281c164408so55990015e9.1 for <72344@debbugs.gnu.org>; Sat, 03 Aug 2024 15:41:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1722724826; x=1723329626; darn=debbugs.gnu.org; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to; bh=5cQFhVV2qGc/Gj69EmlfFgi1sxacw89egnsjAo4mUcs=; b=lojifw5YUSaCZBbx85ujm+C1MwJdsZUnu2dTBrGd9fQ1lYtMX+/yh9ivIdbo9/WcQ9 cFOwX8WWVs2JBkvbPz0hmqblBgbDCZDoWL0sskmMXHq1YowMCy2oVFgY063aNryZZIIy xA1Vv/j0QTUrpbI/GK2tPWWxjpI2a/TRkfJwwXLO7M34XAs0H2YpmAsqsgNvZL9npXPT hfNb9TIwSNIc33EorKDuPP3Ol5xSK75GRkIWGLkwgvqYQSg0jrY9BgXBLtzELzW2x6zx 2QXumru2+/BeTZ9N7berMWszX2Vm1MvpaOkcMsN60bztUZzGlWEMAavAIUg/Y2PALsQQ BLUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722724826; x=1723329626; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=5cQFhVV2qGc/Gj69EmlfFgi1sxacw89egnsjAo4mUcs=; b=Oi4rJbS5F0mWf/otwyYmFEdDdnwUxIlxhCuffZLgRs6M+ES7yKiS68KfLWDiax2yA9 vluE3Iqftmq9mmEa4sKRos7NpS2D0lLSB2mAEWUPbb+jKgpaU1y6uG5zqpEopeO91r/Q SAbf+WVReXyGqvmuwx1wjkzM0Xc+fXZoxCNRDt4ml2tnrC/YK0JzI0Xwufsl6OP9e4sl VwyC4zs4V4nQ8bZULWcIUjcHHvfKoqdrhIlUt9O9DVr/iNrmhOcVtloZzMIiPQWN9iV7 pR5imVAY8KV2T4GaK+/d61HeqrfiURmskd7sN7i4BT3STElJzOOFUxHPAIf3q+3EKt0Z 0oZg== X-Gm-Message-State: AOJu0YyfxmQLAJakAwdlbN2FODcYerwEI3rRMd3MyN5EHEc5viN9/k4D Ls7RVQuSJABqPXK+eMf0bE0LcWlriUhdjXvHr5tDwq6mAkSvUivKpRpe9e2r X-Google-Smtp-Source: AGHT+IEHQIYckJbCeb08dN3csfd1IbqOaJTpwrOCEGRDcNIcZ9oYzJ4EqZdqcv+7ToNwf/jd+60fVg== X-Received: by 2002:a05:600c:a47:b0:427:fa39:b0a1 with SMTP id 5b1f17b1804b1-428e6b930e9mr43873935e9.36.1722724825701; Sat, 03 Aug 2024 15:40:25 -0700 (PDT) Original-Received: from thuna-lis3 ([85.106.105.81]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4282b8adc7dsm139915085e9.14.2024.08.03.15.40.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 03 Aug 2024 15:40:25 -0700 (PDT) In-Reply-To: <87ikwi5neo.fsf@melete.silentflame.com> 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-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:289698 Archived-At: --=-=-= Content-Type: text/plain > Thanks. If you have indeed been coming across this in practice, then it > seems worth adding a macro like this. > > Btw, I think we would want to see an update to cl.texi along with your > change. I've written a draft for what it could look like. It needs proofreading and editing, but it should be a fine-ish place to start from at least. It uses `cl-once-only*' as the name of the macro but that's just a placeholder for now. (Do we want a NEWS entry also?) I've also made it so that the first argument can either be of the form (VARIABLE FORMS) or VARIABLE - how it worked before - which stands for (VARIABLE VARIABLE), so as to keep parity with `cl-once-only'. I've attached the change to cl.texi and the full implementation of `cl-once-only*' as a single patch. >> I don't necessarily think that that name is bad but it doesn't quite get >> to the heart of the macro either. >> >> The macro is meant to be a `cl-once-only' which works on a list of >> forms, and I feel that the "of forms" part is more important than the >> "list" part, which is conceptually more likely to take on a meaning of >> some ambiguous "collection" rather than a chain of cons cells. > > I think we should reserve the starred name for now. As you said, your > macro doesn't come up often, and we might later come up with a variant > of cl-once-only that we want to use very often. I see that point, and it is completely fair. I have no problem conceding the starred name. > cl-seq-once-only ? How about `cl-once-only-multiple'? The name should probably be of the form `cl-once-only', rather than `cl--once-only' I think. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Add-a-version-of-cl-once-only-which-works-on-a-list-.patch >From 18f72562f888d0abe56601544b23358429b7afcd Mon Sep 17 00:00:00 2001 From: Thuna Date: Sun, 4 Aug 2024 00:30:44 +0200 Subject: [PATCH] Add a version of cl-once-only which works on a list of forms --- doc/misc/cl.texi | 49 +++++++++++++++++++++++++++++++++++++- lisp/emacs-lisp/cl-macs.el | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index 113029700ec..57e2f3a6c3b 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -999,7 +999,7 @@ Control Structure * Iteration:: @code{cl-do}, @code{cl-dotimes}, @code{cl-dolist}, @code{cl-do-symbols}. * Loop Facility:: The Common Lisp @code{loop} macro. * Multiple Values:: @code{cl-values}, @code{cl-multiple-value-bind}, etc. -* Macro-Writing Macros:: @code{cl-with-gensyms}, @code{cl-once-only}. +* Macro-Writing Macros:: @code{cl-with-gensyms}, @code{cl-once-only}, @code{cl-once-only*}. @end menu @node Assignment @@ -2683,6 +2683,53 @@ Macro-Writing Macros @end example @end defmac +@defmac cl-once-only* (variable forms) body +This macro is a version of @code{cl-once-only} which takes a list of +forms. This macro is primarily meant to be used where the number of +forms is unknown and thus @code{cl-once-only} cannot work, such as those +obtained by a @code{&body} argument. + +Each element of @var{variable} may be used to refer to the result of +evaluating the corresponding form in @var{forms} within @var{body}. +@code{cl-once-only*} binds @var{variable} to a list of fresh uninterned +symbols. @code{cl-once-only*} furthermore wraps the final expansion +such that each form is evaluated in order and its result is bound to the +corresponding symbol. + +Like @code{cl-once-only}, the first argument can be a symbol +@var{variable}, which is equivalent to writing @code{(variable +variable)}. + +Consider the following macro: + +@example +(defmacro my-list (head &rest args) + (cl-once-only ((args `(list ,@@args)) + `(list (apply #',head ,args) + ,args + (nth 1 ,args)))) +@end example + +This macro is such that it will evaluate @var{args} only once, however +that @var{args} was a list is lost once we are in @code{cl-once-only}. +Furthermore, to access any specific element of @var{args} we must obtain +the element during evaluation via @code{(nth N ,args)}. + +Consider the alternative using @code{cl-once-only*}: + +@example +(defmacro my-list (head &rest args) + (cl-once-only* args + `(list (,head ,@@args) + (list ,@@args) + ,(nth 1 args)))) +@end example + +which preserves the fact that @var{args} is a list and allows immediate +access to individual arguments by simply choosing the corresponding +element in @var{args}. +@end defmac + @node Macros @chapter Macros diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 2e501005bf7..adb9cb29104 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -2544,6 +2544,54 @@ cl-once-only collect `(,(car name) ,gensym)) ,@body))))) +(defmacro cl-once-only* (listvar &rest body) + "Generate code to evaluate the list of FORMS just once in BODY. + +This is a macro to be used while defining other macros. FORMS is +evaluated once during macroexpansion to obtain the list of forms. In +the fully expanded code those forms will be evaluated once before BODY +and their results will be bound to fresh uninterned variables, one for +each form. + +Within the macro VARIABLE is a list of these symbols in order, such that +each form in FORMS can be accessed by using the corresponding element in +VARIABLE. + +The common case of `(cl-once-only* (VARIABLE VARIABLE) ...)' can be +written shortly as `(cl-once-only* VARIABLE ...)'. + +For example, the following macro: + + (defmacro my-list (head &rest args) + (cl-once-only* args + \\=`(list (,head ,@args) ,@args))) + +when called like + + (let ((x \\='(1 5 4))) + (my-list + (pop x) (1+ (pop x)) (1- (pop x)))) + +will expand into + + (let ((x \\='(1 5 4))) + (let* ((arg1 (pop x)) (arg2 (1+ (pop x))) (arg3 (1- (pop x)))) + (list (+ arg1 arg2 arg3) arg1 arg2 arg3))) + +and the arguments will be evaluated only once and in order. + +\(fn (VARIABLE FORMS) &body BODY)" + (declare (debug ([&or symbolp (symbolp form)] body)) (indent 1)) + (let* ((variable (if (symbolp listvar) listvar (nth 0 listvar))) + (forms (if (symbolp listvar) listvar (nth 1 listvar))) + (results* (gensym (symbol-name variable)))) + (cl-once-only (forms) + `(let ((,results* + (cl-loop for i from 1 to (length ,forms) collect + (make-symbol (format "%s$%d" ',(symbol-name variable) i))))) + `(let* ,(cl-mapcar #'list ,results* ,forms) + ,(let ((,variable ,results*)) + ,@body)))))) + ;;; Multiple values. ;;;###autoload -- 2.44.2 --=-=-=--