From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Sean Whitton Newsgroups: gmane.emacs.devel Subject: Re: master 2e9111813b: Add two classic Common Lisp macro-writing macros Date: Tue, 12 Apr 2022 22:48:42 -0700 Message-ID: <87k0btpm85.fsf@athena.silentflame.com> References: <164974332528.14217.12591424007013368601@vcs2.savannah.gnu.org> <20220412060205.8B446C01687@vcs2.savannah.gnu.org> <87wnfux0ok.fsf@yahoo.com> <8735iicfcd.fsf@melete.silentflame.com> <83k0bu3xzc.fsf@gnu.org> 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="26633"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Emacs/29.0.50 (x86_64-pc-linux-gnu) Cc: emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Apr 13 07:51:54 2022 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 1neVuz-0006hF-4q for ged-emacs-devel@m.gmane-mx.org; Wed, 13 Apr 2022 07:51:54 +0200 Original-Received: from localhost ([::1]:49146 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1neVux-0000Ay-Ox for ged-emacs-devel@m.gmane-mx.org; Wed, 13 Apr 2022 01:51:51 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:46032) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1neVs0-000766-QM for emacs-devel@gnu.org; Wed, 13 Apr 2022 01:48:49 -0400 Original-Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:40733) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1neVry-0000mk-Cl; Wed, 13 Apr 2022 01:48:48 -0400 Original-Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.west.internal (Postfix) with ESMTP id 876983202052; Wed, 13 Apr 2022 01:48:44 -0400 (EDT) Original-Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Wed, 13 Apr 2022 01:48:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=spwhitton.name; h=cc:cc:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1649828924; x=1649915324; bh=sh DAq9Au+85fY1E9Zs/P1epclDxTzWK+71678yN1OEU=; b=nYaQJlDacwEoMFOA1c wdOS5rj43H4cX8MxtnqRnOTU8j1z7woqvht9iTcX7qYfQb1PtqbQH45A1wzSeeYo msKBrX3C2s9pwPLQniBwYj5jBY8YASm6ZLPRk87ycOfVokuQeRAStRSRoUjLb9m8 KzJUpPPHsWiqVhOYG8WWGE8GErvfm62mepmQiVtbfySly4vjdx4eUjmE5YJcWVEc EFTraw+qGm4ZC5fTO01B5e74ag+dMZRt0B3rumd8oCCrG7eFUtpirht0A7z4IL7q i51e1JYt3lPp/uZtusv4WNDfnc7LZNgu8xiEYWPbE4j4tLhJHXwjh5FmzHwZsoOf WMqg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1649828924; x= 1649915324; bh=shDAq9Au+85fY1E9Zs/P1epclDxTzWK+71678yN1OEU=; b=A lwJiutMfX/skcBh3gS3vmBNEU5Fe4ddb6bxtNKF+hE3T6X3yzFDOHht6GJumxghB JxRynjNfA9YbKYvX1Nz5LJwiifwJxt3K40Q+jluRt054Ha6i6H4e6FL1QwbgYnzE iGC7yR+H6kusz7PHTiFU3ELaTMYqvJWZHWS8lfJkIct00t0G3MrtAFZbc4SYMSP6 Zuf2r6gQGaOCs7Aa8Yqcl6l5jSQpVDW6bR+ROXerEPaaOniqEtUI6xCHFhITnwKu uvx54jFYr9fj4M1LEKXaPIfVgYsarpzcOHzKYh6eTEXjdEFZs3Yl7xZCol4H5WmW jR76vx500AtfW9FcaCqjw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudekledgleelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufgjfhgffffkgggtsehmtddtredtredtnecuhfhrohhmpefuvggrnhcu hghhihhtthhonhcuoehsphifhhhithhtohhnsehsphifhhhithhtohhnrdhnrghmvgeqne cuggftrfgrthhtvghrnhepgfeuueetvdekffegvdevteehjeeitedvuddvffehvefgtedv gffhteetffdvveejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilh hfrhhomhepshhpfihhihhtthhonhesshhpfihhihhtthhonhdrnhgrmhgv X-ME-Proxy: Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 13 Apr 2022 01:48:43 -0400 (EDT) Original-Received: by athena.silentflame.com (Postfix, from userid 1000) id 357281B7809; Wed, 13 Apr 2022 05:48:42 +0000 (UTC) In-Reply-To: <83k0bu3xzc.fsf@gnu.org> Received-SPF: pass client-ip=64.147.123.20; envelope-from=spwhitton@spwhitton.name; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 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_DNSWL_LOW=-0.7, SPF_HELO_PASS=-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" Xref: news.gmane.io gmane.emacs.devel:288348 Archived-At: --=-=-= Content-Type: text/plain Hello, Thank you for looking! On Tue 12 Apr 2022 at 10:25pm +03, Eli Zaretskii wrote: >> +This macro expands to code that executes @var{body} with each of the >> +variables in @var{names} bound to a fresh uninterned symbol or >> +``gensym''. > > Instead of "or" I suggest to say "a.k.a.@: @dfn{gensym}" (and add a > @cindex entry for "gensym", as usual with any term in @dfn). I've changed this to something else, but I'd prefer not to use an abbreviation like "a.k.a.". Thanks for pointing out @dfn. >> +@defmac cl-once-only ((name form)@dots{}) body@dots{} >> +This macro is primarily to help the macro programmer ensure that forms >> +supplied by the user of the macro are evaluated just once by its >> +expansion even though the result of evaluating the form is to occur >> +more than once. Less often, this macro is used to ensure that forms >> +supplied by the macro programmer are evaluated just once. >> + >> +Each @var{name} is a variable which can be used to refer to the result >> +of evaluating @var{form} in @var{body}. @code{cl-once-only} binds >> +each @var{name} to a fresh uninterned symbol during the evaluation of >> +@var{body}. > > My recommendation is always to try to name parameters after their > roles. In this case, I'd use VAR or VARIABLE instead of the less > specific NAME. Then you could make the text shorter and thus clearer: > > Each @var{variable} can be used to refer to the result of evaluating > @var{form} in @var{body}. @code{cl-once-only} binds each > @var{variable} to a fresh uninterned symbol... Yes, that's better. > (And why not use "gensym" instead of the wordier "uninterned symbol"? > that's why you introduced that terminology, right?) I wanted to use "gensym" in the description of cl-with-gensyms because of the name of that macro. But otherwise, I was thinking that it's a less familiar term in Elisp than it is in CL, and that "uninterned symbol" was the most familiar Elisp term. I don't mind changing it if you think that's not so much of a concern. >> Then, @code{cl-once-only} wraps the final expansion in >> +code to evaluate each @var{form} and bind it to the corresponding >> +uninterned symbol. > > How can a form be bound to a symbol? In this case it should say that the result of evaluation is bound to the corresponding uninterned symbol, thanks. In general, I would describe (let ((x '(+ 1 2))) ...) as a case where a form is bound to a symbol -- would you describe that differently? Revised patch attached. -- Sean Whitton --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Document-additions-of-cl-with-gensyms-and-cl-once-on.patch >From 035d757599c546fffc5acb10a3e692cb2d27d329 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Tue, 12 Apr 2022 11:38:32 -0700 Subject: [PATCH] Document additions of cl-with-gensyms and cl-once-only * NEWS: Document additions of cl-with-gensyms and cl-once-only. * doc/misc/cl.texi (Macro-Writing Macros): New section. (Creating Symbols): Add to the concept index under the name "gensym". (Obsolete Setf Customization): Use cl-once-only rather than macroexp-let2, and fix a quotation bug in one example. --- doc/misc/cl.texi | 86 ++++++++++++++++++++++++++++++++++++++++++++++-- etc/NEWS | 4 +++ 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index a6fe29e102..0946510882 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -843,6 +843,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}. @end menu @node Assignment @@ -2513,6 +2514,86 @@ Multiple Values Since a perfect emulation is not feasible in Emacs Lisp, this package opts to keep it as simple and predictable as possible. +@node Macro-Writing Macros +@section Macro-Writing Macros + +@noindent +This package includes two classic Common Lisp macro-writing macros to +help render complex macrology easier to read. + +@defmac cl-with-gensyms names@dots{} body +This macro expands to code that executes @var{body} with each of the +variables in @var{names} bound to a fresh uninterned symbol, or +@dfn{gensym}, in Common Lisp parlance. For macros requiring more than +one gensym, use of @code{cl-with-gensyms} shortens the code and +renders one's intentions clearer. Compare: + +@example +(defmacro my-macro (foo) + (let ((bar (gensym "bar")) + (baz (gensym "baz")) + (quux (gensym "quux"))) + `(let ((,bar (+ @dots{}))) + @dots{}))) + +(defmacro my-macro (foo) + (cl-with-gensyms (bar baz quux) + `(let ((,bar (+ @dots{}))) + @dots{}))) +@end example +@end defmac + +@defmac cl-once-only ((variable form)@dots{}) body +This macro is primarily to help the macro programmer ensure that forms +supplied by the user of the macro are evaluated just once by its +expansion even though the result of evaluating the form is to occur +more than once. Less often, this macro is used to ensure that forms +supplied by the macro programmer are evaluated just once. + +Each @var{variable} which can be used to refer to the result of +evaluating @var{form} in @var{body}. @code{cl-once-only} binds each +@var{variable} to a fresh uninterned symbol during the evaluation of +@var{body}. Then, @code{cl-once-only} wraps the final expansion in +code to evaluate each @var{form} and bind the result to the +corresponding uninterned symbol. Thus, when the macro writer +substitutes the value for @var{variable} into the expansion they are +effectively referring to the result of evaluating @var{form}, rather +than @var{form} itself. Another way to put this is that each +@var{variable} is bound to an expression for the (singular) result of +evaluating @var{form}. + +The most common case is where @var{variable} is one of the arguments +to the macro being written, so @code{(variable variable)} may be +abbreviated to just @code{variable}. + +For example, consider this macro: + +@example +(defmacro my-list (x y &rest forms) + (let ((x-result (gensym)) + (y-result (gensym))) + `(let ((,x-result ,x) + (,y-result ,y)) + (list ,x-result ,y-result ,x-result ,y-result + (progn ,@@forms)))) +@end example + +In a call like @w{@code{(my-list (pop foo) @dots{})}} the intermediate +binding to @code{x-result} ensures that the @code{pop} is not done +twice. But as a result the code is rather complex: the reader must +keep track of how @code{x-result} really just means the first +parameter of the call to the macro, and the required use of multiple +gensyms to avoid variable capture by @code{(progn ,@@forms)} obscures +things further. @code{cl-once-only} takes care of these details: + +@example +(defmacro my-list (x &rest forms) + (cl-once-only (x y) + `(list ,x ,y ,x ,y + (progn ,@@forms)))) +@end example +@end defmac + @node Macros @chapter Macros @@ -2868,6 +2949,7 @@ Property Lists @node Creating Symbols @section Creating Symbols +@cindex gensym @noindent These functions create unique symbols, typically for use as @@ -5028,13 +5110,13 @@ Obsolete Setf Customization @example (defmacro incf (place &optional n) (gv-letplace (getter setter) place - (macroexp-let2 nil v (or n 1) + (cl-once-only ((v (or n 1))) (funcall setter `(+ ,v ,getter))))) @end example @ignore (defmacro concatf (place &rest args) (gv-letplace (getter setter) place - (macroexp-let2 nil v (mapconcat 'identity args) + (cl-once-only ((v `(mapconcat 'identity ',args))) (funcall setter `(concat ,getter ,v))))) @end ignore @end defmac diff --git a/etc/NEWS b/etc/NEWS index 79c27da549..24e45b0483 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1363,6 +1363,10 @@ functions. +++ ** 'macroexp-let2*' can omit 'test' arg and use single-var bindings. ++++ +** New macro-writing macros, 'cl-with-gensyms' and 'cl-once-only'. +See the '(cl) Macro-Writing Macros' manual section for descriptions. + +++ ** New variable 'last-event-device' and new function 'device-class'. On X Windows, 'last-event-device' specifies the input extension device -- 2.30.2 --=-=-=--