unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#56875: 29.0.50; [PATCH] Add thread-as macro
@ 2022-08-01 17:06 Augusto Stoffel
  2022-08-02  3:40 ` Richard Stallman
  2022-08-02 10:17 ` Lars Ingebrigtsen
  0 siblings, 2 replies; 9+ messages in thread
From: Augusto Stoffel @ 2022-08-01 17:06 UTC (permalink / raw)
  To: 56875

[-- Attachment #1: Type: text/plain, Size: 1062 bytes --]

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


[-- Attachment #2: 0001-Add-thread-as-macro.patch --]
[-- Type: text/x-patch, Size: 1183 bytes --]

From c044cf5891638cd0095db091e86303d683cf380d Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
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


^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-01 17:06 bug#56875: 29.0.50; [PATCH] Add thread-as macro Augusto Stoffel
@ 2022-08-02  3:40 ` Richard Stallman
  2022-08-02  6:57   ` Augusto Stoffel
  2022-08-02 10:17 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 9+ messages in thread
From: Richard Stallman @ 2022-08-02  3:40 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 56875

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Clojure is not really much like Lisp.  Would you please write down the
specs of the construct that you propose we add?  Please make it
self-contained, not assuming any knowledge of Clojure.  We will need that text
as the basis to document it for the Emacs Lisp Reference Manual.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-02  3:40 ` Richard Stallman
@ 2022-08-02  6:57   ` Augusto Stoffel
  0 siblings, 0 replies; 9+ messages in thread
From: Augusto Stoffel @ 2022-08-02  6:57 UTC (permalink / raw)
  To: Richard Stallman; +Cc: 56875

On Mon,  1 Aug 2022 at 23:40, Richard Stallman <rms@gnu.org> wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
> Clojure is not really much like Lisp.  Would you please write down the
> specs of the construct that you propose we add?  Please make it
> self-contained, not assuming any knowledge of Clojure.  We will need that text
> as the basis to document it for the Emacs Lisp Reference Manual.

Did you see the patch attached to my first message?

Concerning documentation, I wrote a docstring with the same level of
detail of the existing thread-first and thread-last, which is on the
terse side but probably sufficient.  WDYT?





^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-01 17:06 bug#56875: 29.0.50; [PATCH] Add thread-as macro Augusto Stoffel
  2022-08-02  3:40 ` Richard Stallman
@ 2022-08-02 10:17 ` Lars Ingebrigtsen
  2022-08-02 11:24   ` Eli Zaretskii
  2022-08-03  3:47   ` Richard Stallman
  1 sibling, 2 replies; 9+ messages in thread
From: Lars Ingebrigtsen @ 2022-08-02 10:17 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 56875, 'Eli Zaretskii'

Augusto Stoffel <arstoffel@gmail.com> writes:

> +(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))

I'm not enthusiastic.  As experience with the other threading macros has
shown, they're neat hacks, but they're not used much in actual code
(because there's no culture for reading code that's formatted that way
in Emacs Lisp).

If others think that this would be useful, I won't object to adding it,
though.  Eli, what do you think?






^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-02 10:17 ` Lars Ingebrigtsen
@ 2022-08-02 11:24   ` Eli Zaretskii
  2022-08-02 12:56     ` Augusto Stoffel
  2022-08-03  3:47   ` Richard Stallman
  1 sibling, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2022-08-02 11:24 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 56875, arstoffel

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: 56875@debbugs.gnu.org, "'Eli Zaretskii'" <eliz@gnu.org>
> Date: Tue, 02 Aug 2022 12:17:09 +0200
> 
> Augusto Stoffel <arstoffel@gmail.com> writes:
> 
> > +(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))
> 
> I'm not enthusiastic.  As experience with the other threading macros has
> shown, they're neat hacks, but they're not used much in actual code
> (because there's no culture for reading code that's formatted that way
> in Emacs Lisp).
> 
> If others think that this would be useful, I won't object to adding it,
> though.  Eli, what do you think?

TBH, I tend to agree.  And I'd like to hear the rationale, to make the
discussion more concrete.  Maybe if the reasons are good enough, I'll
change my mind.  Just looking at the usage, it does sound a bit
artificial.





^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-02 11:24   ` Eli Zaretskii
@ 2022-08-02 12:56     ` Augusto Stoffel
  2022-08-02 13:06       ` Eli Zaretskii
  0 siblings, 1 reply; 9+ messages in thread
From: Augusto Stoffel @ 2022-08-02 12:56 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 56875, Lars Ingebrigtsen

On Tue,  2 Aug 2022 at 14:24, Eli Zaretskii <eliz@gnu.org> wrote:

>> From: Lars Ingebrigtsen <larsi@gnus.org>
>> Cc: 56875@debbugs.gnu.org, "'Eli Zaretskii'" <eliz@gnu.org>
>> Date: Tue, 02 Aug 2022 12:17:09 +0200
>> 
>> Augusto Stoffel <arstoffel@gmail.com> writes:
>> 
>> > +(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))
>> 
>> I'm not enthusiastic.  As experience with the other threading macros has
>> shown, they're neat hacks, but they're not used much in actual code
>> (because there's no culture for reading code that's formatted that way
>> in Emacs Lisp).

I agree that the threading style hasn't become popular in Emacs core.
But some users and package authors rely on it a lot.  Moreover, if 2 of
the 3 basic threading macros are already provided, it seems a bit
incongruent not to offer the third.

Matters of taste aside -- I only use threading occasionally -- I think
it can objectively turn certain really ugly constructs into something
that is at least palatable.

>> If others think that this would be useful, I won't object to adding it,
>> though.  Eli, what do you think?
>
> TBH, I tend to agree.  And I'd like to hear the rationale, to make the
> discussion more concrete.  Maybe if the reasons are good enough, I'll
> change my mind.  Just looking at the usage, it does sound a bit
> artificial.

One concrete example where thread-as would help is in the situation
outlined in the following message, specifically the point that “totally
breaks down if you want to mix in LITERAL etc”:

    https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg01653.html

But since I proposed the macro, maybe I should wait and see if someone
else finds it useful, and in which situation.

(Also, for whatever little it's worth, the macro generates smaller
bytecode than the “just give up and go all imperative” alternative
mentioned in the linked message.)





^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-02 12:56     ` Augusto Stoffel
@ 2022-08-02 13:06       ` Eli Zaretskii
  0 siblings, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2022-08-02 13:06 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 56875, larsi

> From: Augusto Stoffel <arstoffel@gmail.com>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>,  56875@debbugs.gnu.org
> Date: Tue, 02 Aug 2022 14:56:02 +0200
> 
> One concrete example where thread-as would help is in the situation
> outlined in the following message, specifically the point that “totally
> breaks down if you want to mix in LITERAL etc”:
> 
>     https://lists.gnu.org/archive/html/emacs-devel/2021-09/msg01653.html

How frequent that is, and why do you thing using the proposed syntax
makes it less awkward?





^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-02 10:17 ` Lars Ingebrigtsen
  2022-08-02 11:24   ` Eli Zaretskii
@ 2022-08-03  3:47   ` Richard Stallman
  2022-08-05  7:44     ` Augusto Stoffel
  1 sibling, 1 reply; 9+ messages in thread
From: Richard Stallman @ 2022-08-03  3:47 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 56875, eliz, arstoffel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

 > +     (thread-as x
 > +       4
 > +       (- 10 x)
 > +       (/ x 2))

I propose a different syntax which is more Lispy than thread-as, and
more self-evident:

(let-successive ((x 4
                    (- 10 x)))
  (/ x 2))

A Lisper can guess what it means, without having read a description.

It lends itself to a generalization where there is more than
one bound variable, each of which can have several values:

(let-successive ((x 4
                    (- 10 x))
                 (y 6
                    (- 12 y)))
  (* x y))
 => 36

The values after the first can refer to all of the variables,
since all of them are already bound (to the previous values)
at that point.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 9+ messages in thread

* bug#56875: 29.0.50; [PATCH] Add thread-as macro
  2022-08-03  3:47   ` Richard Stallman
@ 2022-08-05  7:44     ` Augusto Stoffel
  0 siblings, 0 replies; 9+ messages in thread
From: Augusto Stoffel @ 2022-08-05  7:44 UTC (permalink / raw)
  To: Richard Stallman; +Cc: 56875, Lars Ingebrigtsen, eliz

On Tue,  2 Aug 2022 at 23:47, Richard Stallman <rms@gnu.org> wrote:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>  > +     (thread-as x
>  > +       4
>  > +       (- 10 x)
>  > +       (/ x 2))
>
> I propose a different syntax which is more Lispy than thread-as, and
> more self-evident:
>
> (let-successive ((x 4
>                     (- 10 x)))
>   (/ x 2))
>
> A Lisper can guess what it means, without having read a description.
>
> It lends itself to a generalization where there is more than
> one bound variable, each of which can have several values:
>
> (let-successive ((x 4
>                     (- 10 x))
>                  (y 6
>                     (- 12 y)))
>   (* x y))
>  => 36
>
> The values after the first can refer to all of the variables,
> since all of them are already bound (to the previous values)
> at that point.

This is an interesting alternative.  I'd suggest to wait for other
opinions about the need for this kind of macro in general, and which
variant is preferred.





^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-08-05  7:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-01 17:06 bug#56875: 29.0.50; [PATCH] Add thread-as macro Augusto Stoffel
2022-08-02  3:40 ` Richard Stallman
2022-08-02  6:57   ` Augusto Stoffel
2022-08-02 10:17 ` Lars Ingebrigtsen
2022-08-02 11:24   ` Eli Zaretskii
2022-08-02 12:56     ` Augusto Stoffel
2022-08-02 13:06       ` Eli Zaretskii
2022-08-03  3:47   ` Richard Stallman
2022-08-05  7:44     ` Augusto Stoffel

Code repositories for project(s) associated with this inbox:

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).