]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new macro 'while-let'
authorLars Ingebrigtsen <larsi@gnus.org>
Wed, 28 Sep 2022 11:19:08 +0000 (13:19 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Wed, 28 Sep 2022 11:19:08 +0000 (13:19 +0200)
* doc/lispref/control.texi (Conditionals): Document
when-let/if-let/while-let.
* lisp/subr.el (while-let): New macro.

doc/lispref/control.texi
etc/NEWS
lisp/subr.el

index ee2acdb002b52ea520fec830ffa973740d257d1f..9635b335bca18329ae8c16e34b23569dfa5c4929 100644 (file)
@@ -294,6 +294,48 @@ For example:
 @end group
 @end example
 
+If can be convenient to bind variables in conjunction with using a
+conditional.  It's often the case that you do a computation, and then
+want to do something with that computation if it's non-@code{nil}.
+The straightforward way to do that is to just write, for instance:
+
+@example
+(let ((result1 (do-computation)))
+  (when result1
+    (let ((result2 (do-more result1)))
+      (when result2
+        (do-something result2)))))
+@end example
+
+Since this is a very common pattern, Emacs provides a number of macros
+to make this easier and more readable.  The above can be written the
+following way instead:
+
+@example
+(when-let ((result1 (do-computation))
+           (result2 (do-more result1)))
+  (do-something result2))
+@end example
+
+There's a number of variations on this theme, and they're briefly
+described below.
+
+@defmac if-let spec then-form else-forms...
+Evaluate each binding in @var{spec} 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}.
+@end defmac
+
+@defmac when-let spec then-forms...
+Like @code{if-let}, but without @var{else-forms}.
+@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}.
+@end defmac
+
 @node Combining Conditions
 @section Constructs for Combining Conditions
 @cindex combining conditions
index b85975944a07b6c9ca5e7fb6854b6de55663f226..e70f9be5468982e98f9b1d995dbd970cb3cdde76 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3012,6 +3012,10 @@ The following generalized variables have been made obsolete:
 \f
 * Lisp Changes in Emacs 29.1
 
++++
+** New macro 'while-let'.
+This is like 'when-let', but repeats until a binding form is nil.
+
 +++
 ** New function 'make-obsolete-generalized-variable'.
 This can be used to mark setters used by 'setf' as obsolete, and the
index 26fba4771bcd759a113211dffc026e5ba9342926..2a8fc46a9f9801148ceb95f1b0dd803981dbb762 100644 (file)
@@ -2514,7 +2514,20 @@ The variable list SPEC is the same as in `if-let'."
   (declare (indent 1) (debug if-let))
   (list 'if-let spec (macroexp-progn body)))
 
+(defmacro while-let (spec &rest body)
+  "Bind variables according to SPEC and conditionally evaluate BODY.
+Evaluate each binding in turn, stopping if a binding value is nil.
+If all bindings are non-nil, eval BODY and repeat.
 
+The variable list SPEC is the same as in `if-let'."
+  (declare (indent 1) (debug if-let))
+  (let ((done (gensym "done")))
+    `(catch ',done
+       (while t
+         (if-let ,spec
+             (progn
+               ,@body)
+           (throw ',done nil))))))
 
 ;; PUBLIC: find if the current mode derives from another.