From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Joost Kremers Newsgroups: gmane.emacs.devel Subject: Re: Is this a bug in while-let or do I missunderstand it? Date: Wed, 13 Nov 2024 00:45:48 +0100 Message-ID: <86ttccvwwj.fsf@fastmail.fm> References: <86ldxrliau.fsf@gnu.org> <865xot2y1d.fsf@fastmail.fm> <86ldxoiqzr.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="16351"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.12.7; emacs 29.4 Cc: arthur.miller@live.com, ams@gnu.org, yuri.v.khan@gmail.com, emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Nov 13 00:46:46 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 1tB0aq-00044G-UG for ged-emacs-devel@m.gmane-mx.org; Wed, 13 Nov 2024 00:46:46 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tB0a7-0003zx-83; Tue, 12 Nov 2024 18:45:59 -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 1tB0a4-0003zZ-Ly for emacs-devel@gnu.org; Tue, 12 Nov 2024 18:45:56 -0500 Original-Received: from fhigh-a2-smtp.messagingengine.com ([103.168.172.153]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tB0a2-0001RA-Gw; Tue, 12 Nov 2024 18:45:56 -0500 Original-Received: from phl-compute-04.internal (phl-compute-04.phl.internal [10.202.2.44]) by mailfhigh.phl.internal (Postfix) with ESMTP id AC2391140196; Tue, 12 Nov 2024 18:45:52 -0500 (EST) Original-Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Tue, 12 Nov 2024 18:45:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fastmail.fm; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1731455152; x=1731541552; bh=aKJ2NVpEDt TzMM3w95gDk356nvRD8uOoMD9WV7lHDEQ=; b=hYSZTPUhImHYRDpzwpfYbovj8X rsYg45093/50Pcarzoh6X3A196DIQSkmFEN3SGKkvWdueqAY8A+Jcq06LocMgaVC KF9tOWl4etVLz4pXlLLFo6DgdR/2LkwFW5SSyfz3Qb+hNSFwi9a+WNWcP4+eBGIC 0GqMcGDsnkMHqOm/3VbhDVZVjKwePAejg36Z1gk9YLF17cv0wAJOIIHZjOGgoh3m MOMSEhdtBfBkaNgLZTFhENx6VVpI8Z8n0SER5wNtsFYi3Mp7VqTLvlahNbKTGAXa R5T+uj65dq3C09E8yOYQhhIXJEV8BwXT3GSe44wbKxyfkDhHZEgtwiAZNFkA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1731455152; x=1731541552; bh=aKJ2NVpEDtTzMM3w95gDk356nvRD8uOoMD9 WV7lHDEQ=; b=ZKsAVtYdXKXUFj5aN+xkjrTrDvOXTgFm9XGhYO70+TIyhN7xpfn E4rdbVMdVBCRxJChgGyw/MQ7n6KNhvVbwnGDsw9ZPQ7C21Odoxg5zbDRffKkqfqi wMi6snvp1c2pAnMo3nOBkvKeDZyp+94Qmn7hXDHysh3+++1YeLQO2vC6/+oFh31T Tm5B1U74AqYTtdnRgvNQw13MfX4AtwvYFF86U5Y13xDepTa8vQN1qGKJgQUONZD8 liAt12nxRta7//MOiL0lyaZf3yGaCHLfMx2d0j9+R/IeNwMfAkrTQVgLFG4RXUUk Nl5BU1DB6fwRKbIiUrcXzvRfssBugPKwsUQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefuddrudehgddufecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdpuffr tefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnth hsucdlqddutddtmdenucfjughrpefhvfevufgjfhgffffkgggtsehmtderredtredtnecu hfhrohhmpeflohhoshhtucfmrhgvmhgvrhhsuceojhhoohhsthhkrhgvmhgvrhhssehfrg hsthhmrghilhdrfhhmqeenucggtffrrghtthgvrhhnpefhiedvteffueduffdtgfduueff ieehleeltdfgvdetueeihedvtdfhkeelvdfgteenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehjohhoshhtkhhrvghmvghrshesfhgrshhtmhgr ihhlrdhfmhdpnhgspghrtghpthhtohephedpmhhouggvpehsmhhtphhouhhtpdhrtghpth htohepvghmrggtshdquggvvhgvlhesghhnuhdrohhrghdprhgtphhtthhopeihuhhrihdr vhdrkhhhrghnsehgmhgrihhlrdgtohhmpdhrtghpthhtoheprghmshesghhnuhdrohhrgh dprhgtphhtthhopegrrhhthhhurhdrmhhilhhlvghrsehlihhvvgdrtghomhdprhgtphht thhopegvlhhiiiesgh X-ME-Proxy: Feedback-ID: ie15541ac:Fastmail Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 12 Nov 2024 18:45:50 -0500 (EST) In-Reply-To: <86ldxoiqzr.fsf@gnu.org> (Eli Zaretskii's message of "Tue, 12 Nov 2024 14:19:36 +0200") Received-SPF: pass client-ip=103.168.172.153; envelope-from=joostkremers@fastmail.fm; helo=fhigh-a2-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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 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:325439 Archived-At: --=-=-= Content-Type: text/plain On Tue, Nov 12 2024, Eli Zaretskii wrote: > Thanks, see some comments below. Second proposal attached. I've accounted for all of your comments. Some replies below: >> >From fb3fd3bef67de821c469c0edb5b1cd6680736565 Mon Sep 17 00:00:00 2001 > One "Like 'when-let*' is borderline-okay; 2 are too many. Please > describe and-let* either completely stand-alone, without relying on > any prior macro, or as "like 'if-let*'" (since it is almost exactly > like if-let*). I didn't write that, that was the documentation until now. :-) In the new patch, I replaced these "Like 'when-let*'" with proper descriptions (worded identically to the extent possible). >> +Each element of the @code{spec} argument in these macros has the form >> +@code{(@var{symbol} @var{value-form})}: @var{value-form} is evaluated >> +and @var{symbol} is locally bound to the result. As a special case, >> +@var{symbol} can be omitted if the result of @var{value-form} just needs >> +to be tested and there's no need to bind it to a variable. > > This paragraph should be before the macros, not after them. I ended up putting it in the description of the first macro (`if-let*`) and referring to it in the others, because the relevant variable (here SPEC) is actually called VARLIST in `if-let*`, `when-let*` and `and-let*`, but SPEC in while-let. (The non-starred versions also have SPEC, but they're being deprecated. BTW, any reason why `while-let` isn't called `while-let*`?) >> +@code{while-let} replaces a pattern in which a binding is established >> +outside the @code{while}-loop, tested as part of the condition of >> +@code{while} and subsequently changed inside the loop using the same >> +expression that it was originally bound to: >> + >> +@example >> +(let ((result (do-computation))) >> + (while result >> + (do-stuff-with result) >> + (setq result (do-computation)))) >> +@end example >> + >> +Using @code{while-let}, this can be written more succinctly as: >> + >> +@example >> +(while-let ((result (do-computation))) >> + (do-stuff-with result)) >> +@end example >> + >> +One crucial difference here is the fact that in the first code example, >> +@code{result} is scoped outside the @code{wile} loop, whereas in the >> +second example, its scope is confined to the @code{while-let} loop. As >> +a result, changing the value of @code{result} inside the loop has no >> +effect on the subsequent iteration. >> +@end defmac > > This is too long a description. I've taken it out completely, and put the most important points in the description of `while-let` directly. Turns out, comparing `while-let` to `while` may even be confusing, because the relevant bindings have different scopes in the two snippets. -- Joost Kremers Life has its moments --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Improve-documentation-for-while-let.patch >From f426c242411b4538e913da31dac7b6b204c288e8 Mon Sep 17 00:00:00 2001 From: Joost Kremers Date: Mon, 11 Nov 2024 23:38:49 +0100 Subject: [PATCH] Improve documentation for `while-let'. * doc/lispref/control.texi: Improve documentation for `while-let`. --- doc/lispref/control.texi | 52 +++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi index 80ed2ce899b..40e23bc2453 100644 --- a/doc/lispref/control.texi +++ b/doc/lispref/control.texi @@ -322,32 +322,56 @@ Conditionals described below. @defmac if-let* varlist then-form else-forms... -Evaluate each binding in @var{varlist} in turn, like in @code{let*} -(@pxref{Local Variables}), stopping if a binding value is @code{nil}. -If all are non-@code{nil}, return the value of @var{then-form}, -otherwise the last form in @var{else-forms}. +Evaluate each binding in @var{varlist}, stopping if a binding value is +@code{nil}. If all are non-@code{nil}, return the value of +@var{then-form}, otherwise the last form in @var{else-forms}. + +Each element of @code{varlist} has the form @code{(@var{symbol} +@var{value-form})}: @var{value-form} is evaluated and @var{symbol} is +locally bound to the result. Bindings are sequential, as in @code{let*} +(@pxref{Local Variables}). As a special case, @var{symbol} can be +omitted if only the test result of @var{value-form} is of interest: +@var{value-form} is evaluated and checked for @code{nil}, but its value +is not bound. @end defmac @defmac when-let* varlist then-forms... -Like @code{if-let*}, but without @var{else-forms}. +Evaluate each binding in @var{varlist}, stopping if a binding value is +@code{nil}. If all are non-@code{nil}, return the value of the last +form in @var{then-forms}. @var{varlist} has the same form as in +@code{if-let*}. @end defmac @defmac and-let* varlist then-forms... -Like @code{when-let*}, but in addition, if there are no -@var{then-forms} and all the bindings evaluate to non-@code{nil}, return -the value of the last binding. -@end defmac - -@defmac while-let spec then-forms... -Like @code{when-let*}, but repeat until a binding in @var{spec} is -@code{nil}. The return value is always @code{nil}. +Evaluate each binding in @var{varlist}, stopping if a binding value is +@code{nil}. If all are non-@code{nil}, return the value of the last +form in @var{then-forms}, or, if there are no @var{then-forms}, return +the value of the last binding. @var{varlist} has the same form as in +@code{if-let*}. @end defmac Some Lisp programmers follow the convention that @code{and} and -@code{and-let*} are for forms evaluated for return value, and +@code{and-let*} are for forms evaluated for their return value, and @code{when} and @code{when-let*} are for forms evaluated for side-effect with returned values ignored. +A similar macro exists to run a loop until one binding evaluates to +@code{nil}: + +@defmac while-let spec then-forms... +Evaluate each binding in @var{spec} in turn, stopping if a binding value +is @code{nil}. If all are non-@code{nil}, execute @var{then-forms}, +then repeat the loop. Note that when the loop is repeated, the +@var{value-forms} in @var{spec} are re-evaluated and the bindings are +established anew. + +@var{spec} has the same form as the @var{varlist} argument in +@code{if-let*}. This means among other things that its bindings are in +sequence, as with @code{let*} (@pxref{Local Variables}). + +The return value of @code{while-let} is always @code{nil}. +@end defmac + @node Combining Conditions @section Constructs for Combining Conditions @cindex combining conditions -- 2.47.0 --=-=-=--