Subject: bug#56875: 29.0.50; [PATCH] Add thread-as macro

From: Augusto Stoffel <[email-masked]>
Date: Mon, 01 Aug 2022 19:06:53 +0200

It has been noted many times that threading macros are not as useful in
Emacs Lisp because the APIs are not always consistent with regard to the
ordering of arguments.  A “thread-as” macro on the lines of Clojure's
'as->' [1] would address this difficulty.

The signature of the Clojure macro is (as-> expr name & forms), which
looks a bit odd to me.  Here I've changed this so the lexical variable
(name) comes before the initial value (expr).

Also, unlike thread-first and thread-last, in the attached version of
the macro there's no magic whereby an element of FORMS which is a
symbol, say fun, is turned into a function call, i.e. (fun name).  In
other words, (thread-as x 1 1+) returns the symbol 1+.  Clojure
behaves the same.  I'm not necessarily against changing the macro so
that the above example returns 2, but I don't see a good reason to do
so either; for one thing, the example gives a byte-compilation warning
(unused lexical variable x).

[1]: https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/as-%3E

>From c044cf5891638cd0095db091e86303d683cf380d Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <[email-masked]>
Date: Mon, 1 Aug 2022 15:59:53 +0200
Subject: [PATCH] Add thread-as macro

* lisp/subr-x.el (thread-as): New macro.
---
 lisp/emacs-lisp/subr-x.el | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index d5d7bfeb6f..916ed39a03 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -81,6 +81,23 @@ thread-last
 threading."
   (declare (indent 0) (debug thread-first))
   `(internal--thread-argument nil ,@forms))
+
+(defmacro thread-as (var &rest forms)
+  "Successively bind VAR to the result of evaluating each of the FORMS.
+Return the last computed value.
+
+Example:
+     (thread-as x
+       4
+       (- 10 x)
+       (/ x 2))
+          ⇒ 3"
+  (declare (indent 1))
+  (if forms
+      `(let ((,var ,(car forms)))
+         (thread-as ,var ,@(cdr forms)))
+    var))
+
 (defsubst hash-table-empty-p (hash-table)
   "Check whether HASH-TABLE is empty (has 0 elements)."
   (zerop (hash-table-count hash-table)))
-- 
2.37.1