bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#28254: 26.0.50; SRFI-2 and-let*


From: Mark Oteiza
Subject: bug#28254: 26.0.50; SRFI-2 and-let*
Date: Sat, 2 Sep 2017 09:36:04 -0400
User-agent: Mutt/1.8.3 (2017-05-23)

On 02/09/17 at 07:25am, Michael Heerdegen wrote:
Mark Oteiza <mvoteiza@udel.edu> writes:

>> I didn't try writing it in the style of if-let*--perhaps if-let* could
>> be extended and all three macros would learn (EXPR).
>
>Yes, I think it's best if all foo-let* macros interpret the varlist in
>the same way.

Alright, I'll look at it.

Isn't there a problem with EXPR being a symbol S, which already has a
different meaning (bind S to nil)?  Though, this seems barely useful to
me.  Anyway, introducing (EXPR) would thus be backward incompatible.

Yeah, that is true.  The following patch implements most of the
previous, except it doesn't specially handle EXPR being just a symbol.
All the incumbent subr-x-tests pass.

This single tuple special case is troublesome IMO:

 (if-let* (x) "dogs" "cats") => "cats"
 (if-let* (x (y 2)) "dogs" "cats") => (void-function y)
 (if-let* (x (y 1) (z 2)) "dogs" "cats") => "cats"

I'm curious if this was brought up in the old discussion when this was
implemented.

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 849ac19d6a..eeacdbcfcd 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -83,10 +83,16 @@ thread-last
  `(internal--thread-argument nil ,@forms))

(defsubst internal--listify (elt)
-  "Wrap ELT in a list if it is not one."
-  (if (not (listp elt))
-      (list elt)
-    elt))
+  "Wrap ELT in a list if it is not one.
+If ELT is of the form ((EXPR)), listify (EXPR) with a dummy symbol."
+  (cond
+   ((nlistp elt) (list elt))
+   ((atom (car elt)) elt)
+   ((and (null (cdr elt))
+         (let ((form (car elt)))
+           (or (listp form) (atom form))))
+    (list (cl-gensym) (car elt)))
+   (t elt)))

(defsubst internal--check-binding (binding)
  "Check BINDING is properly formed."
@@ -122,8 +128,11 @@ if-let*
Each binding is evaluated in turn with `let*', and evaluation
stops if a binding value is nil.  If all are non-nil, the value
of THEN is returned, or the last form in ELSE is returned.
+
Each element of VARLIST is a symbol (which is bound to nil)
or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM).
+An element can additionally be of the form (EXPR), which is
+evaluated and checked for nil.
In the special case you only want to bind a single value,
VARLIST can just be a plain tuple.
\n(fn VARLIST THEN ELSE...)"
@@ -134,18 +143,23 @@ if-let*
             (not (listp (car bindings))))
    ;; Adjust the single binding case
    (setq bindings (list bindings)))
-  `(let* ,(internal--build-bindings bindings)
-     (if ,(car (internal--listify (car (last bindings))))
-         ,then
-       ,@else)))
+  (if bindings
+      `(let* ,(setq bindings (internal--build-bindings bindings))
+         (if ,(caar (last bindings))
+             ,then
+           ,@else))
+    `(let* () ,then)))

(defmacro when-let* (bindings &rest body)
  "Bind variables according to VARLIST and conditionally eval BODY.
Each binding is evaluated in turn with `let*', and evaluation
stops if a binding value is nil.  If all are non-nil, the value
of the last form in BODY is returned.
+
Each element of VARLIST is a symbol (which is bound to nil)
or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM).
+An element can additionally be of the form (EXPR), which is
+evaluated and checked for nil.
In the special case you only want to bind a single value,
VARLIST can just be a plain tuple.
\n(fn VARLIST BODY...)"
@@ -154,7 +168,12 @@ when-let*

(defalias 'if-let 'if-let*)
(defalias 'when-let 'when-let*)
-(defalias 'and-let* 'when-let*)
+
+(defmacro and-let* (varlist &rest body)
+  "Bind variables according to VARLIST and conditionally eval BODY.
+Like `when-let*', except if BODY is empty and all the bindings
+are non-nil, then the result is t."
+  `(when-let* ,varlist ,@(or body '(t))))

(defsubst hash-table-empty-p (hash-table)
  "Check whether HASH-TABLE is empty (has 0 elements)."





reply via email to

[Prev in Thread] Current Thread [Next in Thread]