>   @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}.
>
>The "Like FOO" is confusing -- it is not like when-let*, when-let* is
>also not like let*.  E.g., when spec is (binding value) or just
>(value) (!?) -- which should be mentioned in the manual.
>
>These foo-LET are are mixing up the condition being tested and the
>binding, when there is no binding the form seems to be just a test as
>if you'd pass it directly to WHEN (or whatever).  There should be some
>example that SPEC is not at all like in LET, and that:
>
>(when-let* ((result1 (do-computation))
>            (        (do-more result1)))
>  (do-something result1))
>
>is something like (I guess?):
>
>(let ((result1 (do-computation)))
>  (when result1
>    (when (do-more result1)
>      (do-something result2))))
>
>And these mentions of "Like LET*" should be removed entierly.
>
>But this is a better, and a good start.
>
>   @code{while-let} replaces a common pattern in which a binding is
>   established outside the @{while}-loop, tested as part of the condition of
>   @{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
>
>   The binding of @code{result} is reestablished at every iteration, therefore
>   setting the value of @code{result} inside the loop has no effect. In order
>   to end the loop, @code{(do-computation)} should eventually return
>   @code{nil}.
>
>   This example uses a single binding for clarity, but obviously
>   @code{while-let} can establish multiple bindings. The loop runs as long as
>   all bindings are non-@code{nil}.
>   @end defmac
>   ```
>
>   Am I mistaken or is `while-let` a bit like a do..until loop that some
>   languages offer?

Isn't it also like named-let? But without the ability to call itself recursivey.
I haven't tried it yet, but seems like while-let is a special case of named-let,
an "anonymous named-let" with conditions passed as-they-are. In other words we could
generate while-let as named-let with gensym as the name? (if cl-lib was allowed in
subr.el so to say). I am not sure if I have done it correctly, probably not, but here
is a try:

(defmacro while-test (spec &rest body)
  (declare (indent defun))
  (let* ((name (gensym "while-let-"))
         (bindings (if (and (consp spec) (symbolp (car spec)))
                       (list spec)
                     spec)))
    `(named-let ,name ,spec
       ,@body
       (if (not (and ,@(mapcar #'car bindings)))
           nil
           (,name ,@(mapcar #'cadr bindings))))))

Från: Alfred M. Szmidt <ams@gnu.org>
Skickat: den 10 november 2024 13:10
Till: Joost Kremers <joostkremers@fastmail.fm>
Kopia: eliz@gnu.org <eliz@gnu.org>; arthur.miller@live.com <arthur.miller@live.com>; yuri.v.khan@gmail.com <yuri.v.khan@gmail.com>; emacs-devel@gnu.org <emacs-devel@gnu.org>
Ämne: Re: Is this a bug in while-let or do I missunderstand it?
 
   @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}.

The "Like FOO" is confusing -- it is not like when-let*, when-let* is
also not like let*.  E.g., when spec is (binding value) or just
(value) (!?) -- which should be mentioned in the manual.

These foo-LET are are mixing up the condition being tested and the
binding, when there is no binding the form seems to be just a test as
if you'd pass it directly to WHEN (or whatever).  There should be some
example that SPEC is not at all like in LET, and that:

(when-let* ((result1 (do-computation))
            (        (do-more result1)))
  (do-something result1))

is something like (I guess?):

(let ((result1 (do-computation)))
  (when result1
    (when (do-more result1)
      (do-something result2))))

And these mentions of "Like LET*" should be removed entierly.

But this is a better, and a good start.

   @code{while-let} replaces a common pattern in which a binding is
   established outside the @{while}-loop, tested as part of the condition of
   @{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

   The binding of @code{result} is reestablished at every iteration, therefore
   setting the value of @code{result} inside the loop has no effect. In order
   to end the loop, @code{(do-computation)} should eventually return
   @code{nil}.

   This example uses a single binding for clarity, but obviously
   @code{while-let} can establish multiple bindings. The loop runs as long as
   all bindings are non-@code{nil}.
   @end defmac
   ```

   Am I mistaken or is `while-let` a bit like a do..until loop that some
   languages offer?


   --
   Joost Kremers
   Life has its moments