|
From: | arthur miller |
Subject: | Sv: Is this a bug in while-let or do I missunderstand it? |
Date: | Sun, 10 Nov 2024 19:49:00 +0000 |
> @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 |
[Prev in Thread] | Current Thread | [Next in Thread] |