unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#16963: A patch to create a list-with-tail primitive.
@ 2014-03-07 13:58 Demetrios Obenour
  2014-03-25  2:10 ` Stefan
  2016-02-24  2:51 ` Lars Ingebrigtsen
  0 siblings, 2 replies; 13+ messages in thread
From: Demetrios Obenour @ 2014-03-07 13:58 UTC (permalink / raw)
  To: 16963

Since a comment in backquote.el said that backquote-list* needed to be a
primitive, here is an implementation of it as one, under the name
list-with-tail.

=== modified file 'src/alloc.c'
--- src/alloc.c	2014-02-28 21:45:34 +0000
+++ src/alloc.c	2014-03-07 13:27:33 +0000
@@ -2593,6 +2593,26 @@
   return val;
 }
 
+DEFUN ("list-with-tail", Flist_with_tail, Slist_with_tail, 0, MANY, 0,
+       doc: /* Return a newly created list with specified arguments as
elements,
+except for the last argument, which becomes the tail of the list.
+At least one argument is required.
+usage: (list &rest OBJECTS &last TAIL)  */)
+  (ptrdiff_t nargs, Lisp_Object *args)
+{
+  if (nargs == 0)
+    error ("Wrong number of arguments");
+  register Lisp_Object val;
+  nargs--;
+  val = args[nargs];
+
+  while (nargs > 0)
+    {
+      nargs--;
+      val = Fcons (args[nargs], val);
+    }
+  return val;
+}
 
 DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
        doc: /* Return a newly created list of length LENGTH, with each
element being INIT.  */)
@@ -6921,6 +6941,7 @@
 
   defsubr (&Scons);
   defsubr (&Slist);
+  defsubr (&Slist_with_tail);
   defsubr (&Svector);
   defsubr (&Smake_byte_code);
   defsubr (&Smake_list);


Change Log:

  This creates a built-in function, list-with-tail,
  that is identical to backquote-list*-function
  in backquote.el except that it is a primitive.
  This follows the suggestion made in a backquote.el

Sincerely,

Demetrios Obenour






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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-07 13:58 bug#16963: A patch to create a list-with-tail primitive Demetrios Obenour
@ 2014-03-25  2:10 ` Stefan
  2014-03-25  2:45   ` Daniel Colascione
  2016-02-24  2:51 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 13+ messages in thread
From: Stefan @ 2014-03-25  2:10 UTC (permalink / raw)
  To: Demetrios Obenour; +Cc: 16963

> Since a comment in backquote.el said that backquote-list* needed to be a
> primitive, here is an implementation of it as one, under the name
> list-with-tail.

I think it would make more sense to call it `list*'.  Also it might make
sense to change backquote.el so it uses this `list*' (tho probably only
when passed with enough arguments).


        Stefan





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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-25  2:10 ` Stefan
@ 2014-03-25  2:45   ` Daniel Colascione
  2014-03-27 23:37     ` Demetrios Obenour
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Colascione @ 2014-03-25  2:45 UTC (permalink / raw)
  To: Stefan, Demetrios Obenour; +Cc: 16963

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

On 03/24/2014 07:10 PM, Stefan wrote:
>> Since a comment in backquote.el said that backquote-list* needed to be a
>> primitive, here is an implementation of it as one, under the name
>> list-with-tail.
> 
> I think it would make more sense to call it `list*'.  Also it might make
> sense to change backquote.el so it uses this `list*' (tho probably only
> when passed with enough arguments).

Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
If you do add this feature, please make sure the existing list* compiler
macros keep working.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-25  2:45   ` Daniel Colascione
@ 2014-03-27 23:37     ` Demetrios Obenour
  2014-03-27 23:38       ` Daniel Colascione
  0 siblings, 1 reply; 13+ messages in thread
From: Demetrios Obenour @ 2014-03-27 23:37 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: 16963

On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
> On 03/24/2014 07:10 PM, Stefan wrote:
> >> Since a comment in backquote.el said that backquote-list* needed to be a
> >> primitive, here is an implementation of it as one, under the name
> >> list-with-tail.
> > 
> > I think it would make more sense to call it `list*'.  Also it might make
> > sense to change backquote.el so it uses this `list*' (tho probably only
> > when passed with enough arguments).
> 
> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
> If you do add this feature, please make sure the existing list* compiler
> macros keep working.
> 
What about just deleting these compiler macros, and making cl-list* an
alias for list*?

There seems to be little point in keeping them if list* is a primitive.






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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-27 23:37     ` Demetrios Obenour
@ 2014-03-27 23:38       ` Daniel Colascione
  2014-03-28  0:43         ` Demetrios Obenour
  2014-03-29  1:46         ` Demetrios Obenour
  0 siblings, 2 replies; 13+ messages in thread
From: Daniel Colascione @ 2014-03-27 23:38 UTC (permalink / raw)
  To: Demetrios Obenour; +Cc: 16963

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

On 03/27/2014 04:37 PM, Demetrios Obenour wrote:
> On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
>> On 03/24/2014 07:10 PM, Stefan wrote:
>>>> Since a comment in backquote.el said that backquote-list* needed to be a
>>>> primitive, here is an implementation of it as one, under the name
>>>> list-with-tail.
>>>
>>> I think it would make more sense to call it `list*'.  Also it might make
>>> sense to change backquote.el so it uses this `list*' (tho probably only
>>> when passed with enough arguments).
>>
>> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
>> If you do add this feature, please make sure the existing list* compiler
>> macros keep working.
>>
> What about just deleting these compiler macros, and making cl-list* an
> alias for list*?
> 
> There seems to be little point in keeping them if list* is a primitive.

The new list* doesn't have an opcode, but cons does.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-27 23:38       ` Daniel Colascione
@ 2014-03-28  0:43         ` Demetrios Obenour
  2014-03-29  1:46         ` Demetrios Obenour
  1 sibling, 0 replies; 13+ messages in thread
From: Demetrios Obenour @ 2014-03-28  0:43 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: 16963

On Thu, 2014-03-27 at 16:38 -0700, Daniel Colascione wrote:
> On 03/27/2014 04:37 PM, Demetrios Obenour wrote:
> > On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
> >> On 03/24/2014 07:10 PM, Stefan wrote:
> >>>> Since a comment in backquote.el said that backquote-list* needed to be a
> >>>> primitive, here is an implementation of it as one, under the name
> >>>> list-with-tail.
> >>>
> >>> I think it would make more sense to call it `list*'.  Also it might make
> >>> sense to change backquote.el so it uses this `list*' (tho probably only
> >>> when passed with enough arguments).
> >>
> >> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
> >> If you do add this feature, please make sure the existing list* compiler
> >> macros keep working.
> >>
> > What about just deleting these compiler macros, and making cl-list* an
> > alias for list*?
> > 
> > There seems to be little point in keeping them if list* is a primitive.
> 
> The new list* doesn't have an opcode, but cons does.
> 

Ah I see -- there might be a speed advantage in repeated cons calls, up
to a point. At what point would the function look-up be slower than
repeated function calls (I thought that function calls in Emacs Lisp are
slow)?






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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-27 23:38       ` Daniel Colascione
  2014-03-28  0:43         ` Demetrios Obenour
@ 2014-03-29  1:46         ` Demetrios Obenour
  2014-03-29  1:48           ` Daniel Colascione
  1 sibling, 1 reply; 13+ messages in thread
From: Demetrios Obenour @ 2014-03-29  1:46 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: 16963

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

On Thu, 2014-03-27 at 16:38 -0700, Daniel Colascione wrote:
> On 03/27/2014 04:37 PM, Demetrios Obenour wrote:
> > On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
> >> On 03/24/2014 07:10 PM, Stefan wrote:
> >>>> Since a comment in backquote.el said that backquote-list* needed to be a
> >>>> primitive, here is an implementation of it as one, under the name
> >>>> list-with-tail.
> >>>
> >>> I think it would make more sense to call it `list*'.  Also it might make
> >>> sense to change backquote.el so it uses this `list*' (tho probably only
> >>> when passed with enough arguments).
> >>
> >> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
> >> If you do add this feature, please make sure the existing list* compiler
> >> macros keep working.
> >>
> > What about just deleting these compiler macros, and making cl-list* an
> > alias for list*?
> > 
> > There seems to be little point in keeping them if list* is a primitive.
> 
> The new list* doesn't have an opcode, but cons does.
> 
Good point! My testing showed four nested cons calls to be much faster
than list* with five arguments by several dozen times.

Maybe list* should be a macro instead?



[-- Attachment #2: Type: text/html, Size: 2268 bytes --]

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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-29  1:46         ` Demetrios Obenour
@ 2014-03-29  1:48           ` Daniel Colascione
  2014-03-29 13:30             ` Demetrios Obenour
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Colascione @ 2014-03-29  1:48 UTC (permalink / raw)
  To: Demetrios Obenour; +Cc: 16963

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

On 03/28/2014 06:46 PM, Demetrios Obenour wrote:
> On Thu, 2014-03-27 at 16:38 -0700, Daniel Colascione wrote:
>> On 03/27/2014 04:37 PM, Demetrios Obenour wrote:
>> > On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
>> >> On 03/24/2014 07:10 PM, Stefan wrote:
>> >>>> Since a comment in backquote.el said that backquote-list* needed to be a
>> >>>> primitive, here is an implementation of it as one, under the name
>> >>>> list-with-tail.
>> >>>
>> >>> I think it would make more sense to call it `list*'.  Also it might make
>> >>> sense to change backquote.el so it uses this `list*' (tho probably only
>> >>> when passed with enough arguments).
>> >>
>> >> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
>> >> If you do add this feature, please make sure the existing list* compiler
>> >> macros keep working.
>> >>
>> > What about just deleting these compiler macros, and making cl-list* an
>> > alias for list*?
>> > 
>> > There seems to be little point in keeping them if list* is a primitive.
>> 
>> The new list* doesn't have an opcode, but cons does.
>> 
> Good point! My testing showed four nested cons calls to be much faster
> than list* with five arguments by several dozen times.
> 
> Maybe list* should be a macro instead?

No, list* as a function is perfectly fine --- we might want to call it
indirectly sometimes, e.g., with apply. The compiler macro is sufficient
to convert it to cons calls when we know it's safe. M-x disassemble is
your friend. :-)


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-29  1:48           ` Daniel Colascione
@ 2014-03-29 13:30             ` Demetrios Obenour
  0 siblings, 0 replies; 13+ messages in thread
From: Demetrios Obenour @ 2014-03-29 13:30 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: 16963

On Fri, 2014-03-28 at 18:48 -0700, Daniel Colascione wrote:
> On 03/28/2014 06:46 PM, Demetrios Obenour wrote:
> > On Thu, 2014-03-27 at 16:38 -0700, Daniel Colascione wrote:
> >> On 03/27/2014 04:37 PM, Demetrios Obenour wrote:
> >> > On Mon, 2014-03-24 at 19:45 -0700, Daniel Colascione wrote:
> >> >> On 03/24/2014 07:10 PM, Stefan wrote:
> >> >>>> Since a comment in backquote.el said that backquote-list* needed to be a
> >> >>>> primitive, here is an implementation of it as one, under the name
> >> >>>> list-with-tail.
> >> >>>
> >> >>> I think it would make more sense to call it `list*'.  Also it might make
> >> >>> sense to change backquote.el so it uses this `list*' (tho probably only
> >> >>> when passed with enough arguments).
> >> >>
> >> >> Agreed. On more that one occasion, I've wished we had a CL-less `list*'.
> >> >> If you do add this feature, please make sure the existing list* compiler
> >> >> macros keep working.
> >> >>
> >> > What about just deleting these compiler macros, and making cl-list* an
> >> > alias for list*?
> >> > 
> >> > There seems to be little point in keeping them if list* is a primitive.
> >> 
> >> The new list* doesn't have an opcode, but cons does.
> >> 
> > Good point! My testing showed four nested cons calls to be much faster
> > than list* with five arguments by several dozen times.
> > 
> > Maybe list* should be a macro instead?
> 
> No, list* as a function is perfectly fine --- we might want to call it
> indirectly sometimes, e.g., with apply. The compiler macro is sufficient
> to convert it to cons calls when we know it's safe. M-x disassemble is
> your friend. :-)
> 
Ah thanks!

Here is a patch to fix the Lisp files to exploit a list* primitive.

=== modified file 'lisp/emacs-lisp/cl-lib.el'
--- lisp/emacs-lisp/cl-lib.el	2014-01-01 07:43:34 +0000
+++ lisp/emacs-lisp/cl-lib.el	2014-03-29 13:12:10 +0000
@@ -527,19 +527,13 @@
 ;;    (while (consp (cdr x)) (pop x))
 ;;    x))
 
-(defun cl-list* (arg &rest rest)
+(defalias 'cl-list* (symbol-function 'list*)
   "Return a new list with specified ARGs as elements, consed to last
ARG.
 Thus, `(cl-list* A B C D)' is equivalent to `(nconc (list A B C) D)',
or to
 `(cons A (cons B (cons C D)))'.
-\n(fn ARG...)"
-  (declare (compiler-macro cl--compiler-macro-list*))
-  (cond ((not rest) arg)
-	((not (cdr rest)) (cons arg (car rest)))
-	(t (let* ((n (length rest))
-		  (copy (copy-sequence rest))
-		  (last (nthcdr (- n 2) copy)))
-	     (setcdr last (car (cdr last)))
-	     (cons arg copy)))))
+\n(fn ARG...)")
+(put 'list* 'compiler-macro #'cl--compiler-macro-list*)
+(put 'cl-list* 'compiler-macro #'cl--compiler-macro-list*)
 
 (defun cl-ldiff (list sublist)
   "Return a copy of LIST with the tail SUBLIST removed."

=== modified file 'lisp/emacs-lisp/cl.el'
--- lisp/emacs-lisp/cl.el	2014-01-01 07:43:34 +0000
+++ lisp/emacs-lisp/cl.el	2014-03-29 12:58:27 +0000
@@ -257,7 +257,6 @@
                adjoin
                copy-list
                ldiff
-               list*
                cddddr
                cdddar
                cddadr








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

* bug#16963: A patch to create a list-with-tail primitive.
  2014-03-07 13:58 bug#16963: A patch to create a list-with-tail primitive Demetrios Obenour
  2014-03-25  2:10 ` Stefan
@ 2016-02-24  2:51 ` Lars Ingebrigtsen
  2019-06-26 14:30   ` Lars Ingebrigtsen
  1 sibling, 1 reply; 13+ messages in thread
From: Lars Ingebrigtsen @ 2016-02-24  2:51 UTC (permalink / raw)
  To: Demetrios Obenour; +Cc: 16963

Demetrios Obenour <demetriobenour@gmail.com> writes:

> Since a comment in backquote.el said that backquote-list* needed to be a
> primitive, here is an implementation of it as one, under the name
> list-with-tail.

[...]

> -(defun cl-list* (arg &rest rest)
> +(defalias 'cl-list* (symbol-function 'list*)
>    "Return a new list with specified ARGs as elements, consed to last

Reading this bug report, there seemed to be general agreement that Emacs
should have `list*', and that `cl-list*' should be an alias for it, but
these patches were not applied.

I can't find your name in the Emacs copyright assignment file -- would
you be willing to sign a copyright assignment to the FSF?

And then, could you re-spin the patches, along with changes to the
lispref manual as needed (and an etc/NEWS entry)?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#16963: A patch to create a list-with-tail primitive.
  2016-02-24  2:51 ` Lars Ingebrigtsen
@ 2019-06-26 14:30   ` Lars Ingebrigtsen
  2019-06-28  3:14     ` Noam Postavsky
  0 siblings, 1 reply; 13+ messages in thread
From: Lars Ingebrigtsen @ 2019-06-26 14:30 UTC (permalink / raw)
  To: Demetrios Obenour; +Cc: 16963

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Reading this bug report, there seemed to be general agreement that Emacs
> should have `list*', and that `cl-list*' should be an alias for it, but
> these patches were not applied.
>
> I can't find your name in the Emacs copyright assignment file -- would
> you be willing to sign a copyright assignment to the FSF?

I asked that three years ago, when the patch was already two years old,
so I'm guessing that this is not going to happen, so I'm closing this
bug report.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#16963: A patch to create a list-with-tail primitive.
  2019-06-26 14:30   ` Lars Ingebrigtsen
@ 2019-06-28  3:14     ` Noam Postavsky
  2019-06-28  3:30       ` Drew Adams
  0 siblings, 1 reply; 13+ messages in thread
From: Noam Postavsky @ 2019-06-28  3:14 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 16963, Demetrios Obenour

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

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Lars Ingebrigtsen <larsi@gnus.org> writes:
>
>> Reading this bug report, there seemed to be general agreement that Emacs
>> should have `list*', and that `cl-list*' should be an alias for it, but
>> these patches were not applied.
>>
>> I can't find your name in the Emacs copyright assignment file -- would
>> you be willing to sign a copyright assignment to the FSF?
>
> I asked that three years ago, when the patch was already two years old,
> so I'm guessing that this is not going to happen, so I'm closing this
> bug report.

Oh, this reminds me I had started writing a patch for this.  I used the
name cons* instead of list* though, I always found it more logical:
cons* is cons repeated, just like let* is let repeated.  Let me dust it
off:


[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 19149 bytes --]

From e44291e055b167548a9b5166764e144644cc6291 Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Sun, 2 Jul 2017 17:44:02 -0400
Subject: [PATCH] Implement cons* as a C subroutine (Bug#16963)

* src/alloc.c (Fcons_star): New subr.
* doc/lispref/lists.texi (Building Lists): Document it.
* etc/NEWS: Announce it.
* lisp/emacs-lisp/cl-macs.el (cl--compiler-macro-list*): Move to...
* lisp/subr.el (internal--compiler-macro-cons*): ...here, and rename.
Set as compiler-macro for `cons*'.
* lisp/emacs-lisp/backquote.el (backquote-list*-function)
(backquote-list*-macro, backquote-list*): Remove.
(backquote-listify):
* lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/inline.el (inline--do-quote):
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Replace
`backquote-list*' with `cons*'.
* lisp/emacs-lisp/cl-lib.el (cl-list*): Make into alias for `cons*'.
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all): Change special
case for `backquote-list*' macro to special case for
`internal--compiler-macro-cons*' compiler-macro.
---
 doc/lispref/lists.texi       |  18 +++++
 etc/NEWS                     |   3 +
 lisp/emacs-lisp/backquote.el |  50 +-------------
 lisp/emacs-lisp/byte-opt.el  |   2 +-
 lisp/emacs-lisp/cl-lib.el    |  15 +---
 lisp/emacs-lisp/cl-macs.el   |   8 ---
 lisp/emacs-lisp/inline.el    |   2 +-
 lisp/emacs-lisp/macroexp.el  | 161 +++++++++++++++++++++----------------------
 lisp/subr.el                 |   9 +++
 src/alloc.c                  |  13 ++++
 10 files changed, 129 insertions(+), 152 deletions(-)

diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi
index 746b4643c1..a398721c79 100644
--- a/doc/lispref/lists.texi
+++ b/doc/lispref/lists.texi
@@ -503,6 +503,24 @@ Building Lists
 @end example
 @end defun
 
+@defun cons* object1 &rest objects
+This function is similar to @code{list}, but instead of terminating
+the returned list with @code{nil}, it uses the last argument instead.
+This is mainly useful when adding several elements to a list, to avoid
+having to call @code{cons} repeatedly.  For example:
+
+@example
+(setq list (cons* newelt1 newelt2 list))
+@end example
+
+is equivalent to
+
+@example
+(setq list (cons newelt1 (cons newelt2 list)))
+@end example
+
+@end defun
+
 @defun make-list length object
 This function creates a list of @var{length} elements, in which each
 element is @var{object}.  Compare @code{make-list} with
diff --git a/etc/NEWS b/etc/NEWS
index b1f1f7293a..06d5e93d02 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1862,6 +1862,9 @@ according to the given numeric value.
 ** 'condition-case' now accepts 't' to match any error symbol.
 
 +++
+** New subr 'cons*'.
+
++++
 ** New function 'proper-list-p'.
 Given a proper list as argument, this predicate returns its length;
 otherwise, it returns nil.  'format-proper-list-p' is now an obsolete
diff --git a/lisp/emacs-lisp/backquote.el b/lisp/emacs-lisp/backquote.el
index 5e72dc3b40..fd31d82728 100644
--- a/lisp/emacs-lisp/backquote.el
+++ b/lisp/emacs-lisp/backquote.el
@@ -29,56 +29,10 @@
 ;; When it sees ,... inside such a backquote form, it generates (\, ...).
 ;; For ,@... it generates (\,@ ...).
 
-;; This backquote will generate calls to the backquote-list* form.
-;; Both a function version and a macro version are included.
-;; The macro version is used by default because it is faster
-;; and needs no run-time support.  It should really be a subr.
-
 ;;; Code:
 
 (provide 'backquote)
 
-;; function and macro versions of backquote-list*
-
-(defun backquote-list*-function (first &rest list)
-  "Like `list' but the last argument is the tail of the new list.
-
-For example (backquote-list* \\='a \\='b \\='c) => (a b . c)"
-  ;; The recursive solution is much nicer:
-  ;; (if list (cons first (apply 'backquote-list*-function list)) first))
-  ;; but Emacs is not very good at efficiently processing recursion.
-  (if list
-      (let* ((rest list) (newlist (cons first nil)) (last newlist))
-	(while (cdr rest)
-	  (setcdr last (cons (car rest) nil))
-	  (setq last (cdr last)
-		rest (cdr rest)))
-	(setcdr last (car rest))
-	newlist)
-    first))
-
-(defmacro backquote-list*-macro (first &rest list)
-  "Like `list' but the last argument is the tail of the new list.
-
-For example (backquote-list* \\='a \\='b \\='c) => (a b . c)"
-  ;; The recursive solution is much nicer:
-  ;; (if list (list 'cons first (cons 'backquote-list*-macro list)) first))
-  ;; but Emacs is not very good at efficiently processing such things.
-  (setq list (nreverse (cons first list))
-	first (car list)
-	list (cdr list))
-  (if list
-      (let* ((second (car list))
-	     (rest (cdr list))
-	     (newlist (list 'cons second first)))
-	(while rest
-	  (setq newlist (list 'cons (car rest) newlist)
-		rest (cdr rest)))
-	newlist)
-    first))
-
-(defalias 'backquote-list* (symbol-function 'backquote-list*-macro))
-
 ;; A few advertised variables that control which symbols are used
 ;; to represent the backquote, unquote, and splice operations.
 (defconst backquote-backquote-symbol '\`
@@ -219,7 +173,7 @@ backquote-process
       (cons (if (eq (car-safe expression) 'quote) 0 1) expression)))))
 
 ;; backquote-listify takes (tag . structure) pairs from backquote-process
-;; and decides between append, list, backquote-list*, and cons depending
+;; and decides between append, list, cons*, and cons depending
 ;; on which tags are in the list.
 
 (defun backquote-listify (list old-tail)
@@ -242,7 +196,7 @@ backquote-listify
 			       (and (consp (car heads))
 				    (eq (car (car heads))
 					backquote-splice-symbol)))))
-	    (cons (if use-list* 'backquote-list* 'cons)
+            (cons (if use-list* 'cons* 'cons)
 		  (append heads (list tail))))
 	tail))
      (t (cons 'list heads)))))
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 2e09601639..0e53ab85ec 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1168,7 +1168,7 @@ byte-optimize-set
 	 buffer-substring byte-code-function-p
 	 capitalize car-less-than-car car cdr ceiling char-after char-before
 	 char-equal char-to-string char-width compare-strings
-	 compare-window-configurations concat coordinates-in-window-p
+         compare-window-configurations concat cons* coordinates-in-window-p
 	 copy-alist copy-sequence copy-marker cos count-lines
 	 current-time-string current-time-zone
 	 decode-char
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index c51c70d317..2f1274b71e 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -434,19 +434,8 @@ 'cl-cddddr
 ;;    (while (consp (cdr x)) (pop x))
 ;;    x))
 
-(defun cl-list* (arg &rest rest)
-  "Return a new list with specified ARGs as elements, consed to last ARG.
-Thus, `(cl-list* A B C D)' is equivalent to `(nconc (list A B C) D)', or to
-`(cons A (cons B (cons C D)))'.
-\n(fn ARG...)"
-  (declare (compiler-macro cl--compiler-macro-list*))
-  (cond ((not rest) arg)
-	((not (cdr rest)) (cons arg (car rest)))
-	(t (let* ((n (length rest))
-		  (copy (copy-sequence rest))
-		  (last (nthcdr (- n 2) copy)))
-	     (setcdr last (car (cdr last)))
-	     (cons arg copy)))))
+(defalias 'cl-list* 'cons*)
+(function-put 'cl-list* 'compiler-macro #'internal--compiler-macro-cons*)
 
 (defun cl-ldiff (list sublist)
   "Return a copy of LIST with the tail SUBLIST removed."
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 54974ceb7d..18b6707655 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -62,14 +62,6 @@ cl--optimize-speed
 ;; functions can lead to recursive-loads that prevent the calls from
 ;; being optimized.
 
-;;;###autoload
-(defun cl--compiler-macro-list* (_form arg &rest others)
-  (let* ((args (reverse (cons arg others)))
-	 (form (car args)))
-    (while (setq args (cdr args))
-      (setq form `(cons ,(car args) ,form)))
-    form))
-
 ;; Note: `cl--compiler-macro-cXXr' has been copied to
 ;; `internal--compiler-macro-cXXr' in subr.el.  If you amend either
 ;; one, you may want to amend the other, too.
diff --git a/lisp/emacs-lisp/inline.el b/lisp/emacs-lisp/inline.el
index 70dbff2147..25aee42db2 100644
--- a/lisp/emacs-lisp/inline.el
+++ b/lisp/emacs-lisp/inline.el
@@ -185,7 +185,7 @@ inline--do-quote
          (push (inline--do-quote (pop exp)) args))
        (setq args (nreverse args))
        (if exp
-           `(backquote-list* ,@args ,(inline--do-quote exp))
+           `(cons* ,@args ,(inline--do-quote exp))
          `(list ,@args))))
     (_ (macroexp-quote exp))))
 
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index 9af75320ec..fd5a2864ce 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -201,85 +201,84 @@ macroexp--expand-all
   "Expand all macros in FORM.
 This is an internal version of `macroexpand-all'.
 Assumes the caller has bound `macroexpand-all-environment'."
-  (if (eq (car-safe form) 'backquote-list*)
-      ;; Special-case `backquote-list*', as it is normally a macro that
-      ;; generates exceedingly deep expansions from relatively shallow input
-      ;; forms.  We just process it `in reverse' -- first we expand all the
-      ;; arguments, _then_ we expand the top-level definition.
-      (macroexpand (macroexp--all-forms form 1)
-		   macroexpand-all-environment)
-    ;; Normal form; get its expansion, and then expand arguments.
-    (setq form (macroexp-macroexpand form macroexpand-all-environment))
-    (pcase form
-      (`(cond . ,clauses)
-       (macroexp--cons 'cond (macroexp--all-clauses clauses) form))
-      (`(condition-case . ,(or `(,err ,body . ,handlers) dontcare))
-       (macroexp--cons
-        'condition-case
-        (macroexp--cons err
-                        (macroexp--cons (macroexp--expand-all body)
-                                        (macroexp--all-clauses handlers 1)
-                                        (cddr form))
-                        (cdr form))
-        form))
-      (`(,(or 'defvar 'defconst) . ,_) (macroexp--all-forms form 2))
-      (`(function ,(and f `(lambda . ,_)))
-       (macroexp--cons 'function
-                       (macroexp--cons (macroexp--all-forms f 2)
-                                       nil
-                                       (cdr form))
-                       form))
-      (`(,(or 'function 'quote) . ,_) form)
-      (`(,(and fun (or 'let 'let*)) . ,(or `(,bindings . ,body) dontcare))
-       (macroexp--cons fun
-                       (macroexp--cons (macroexp--all-clauses bindings 1)
-                                       (macroexp--all-forms body)
-                                       (cdr form))
-                       form))
-      (`(,(and fun `(lambda . ,_)) . ,args)
-       ;; Embedded lambda in function position.
-       (macroexp--cons (macroexp--all-forms fun 2)
-                       (macroexp--all-forms args)
-                       form))
-      ;; The following few cases are for normal function calls that
-      ;; are known to funcall one of their arguments.  The byte
-      ;; compiler has traditionally handled these functions specially
-      ;; by treating a lambda expression quoted by `quote' as if it
-      ;; were quoted by `function'.  We make the same transformation
-      ;; here, so that any code that cares about the difference will
-      ;; see the same transformation.
-      ;; First arg is a function:
-      (`(,(and fun (or 'funcall 'apply 'mapcar 'mapatoms 'mapconcat 'mapc))
-         ',(and f `(lambda . ,_)) . ,args)
-       (macroexp--warn-and-return
-        (format "%s quoted with ' rather than with #'"
-                (list 'lambda (nth 1 f) '...))
-        (macroexp--expand-all `(,fun ,f . ,args))))
-      ;; Second arg is a function:
-      (`(,(and fun (or 'sort)) ,arg1 ',(and f `(lambda . ,_)) . ,args)
-       (macroexp--warn-and-return
-        (format "%s quoted with ' rather than with #'"
-                (list 'lambda (nth 1 f) '...))
-        (macroexp--expand-all `(,fun ,arg1 ,f . ,args))))
-      (`(funcall #',(and f (pred symbolp)) . ,args)
-       ;; Rewrite (funcall #'foo bar) to (foo bar), in case `foo'
-       ;; has a compiler-macro.
-       (macroexp--expand-all `(,f . ,args)))
-      (`(,func . ,_)
-       ;; Macro expand compiler macros.  This cannot be delayed to
-       ;; byte-optimize-form because the output of the compiler-macro can
-       ;; use macros.
-       (let ((handler (function-get func 'compiler-macro)))
-         (if (null handler)
-             ;; No compiler macro.  We just expand each argument (for
-             ;; setq/setq-default this works alright because the variable names
-             ;; are symbols).
-             (macroexp--all-forms form 1)
-           ;; If the handler is not loaded yet, try (auto)loading the
-           ;; function itself, which may in turn load the handler.
-           (unless (functionp handler)
-             (with-demoted-errors "macroexp--expand-all: %S"
-               (autoload-do-load (indirect-function func) func)))
+  ;; Normal form; get its expansion, and then expand arguments.
+  (setq form (macroexp-macroexpand form macroexpand-all-environment))
+  (pcase form
+    (`(cond . ,clauses)
+     (macroexp--cons 'cond (macroexp--all-clauses clauses) form))
+    (`(condition-case . ,(or `(,err ,body . ,handlers) dontcare))
+     (macroexp--cons
+      'condition-case
+      (macroexp--cons err
+                      (macroexp--cons (macroexp--expand-all body)
+                                      (macroexp--all-clauses handlers 1)
+                                      (cddr form))
+                      (cdr form))
+      form))
+    (`(,(or 'defvar 'defconst) . ,_) (macroexp--all-forms form 2))
+    (`(function ,(and f `(lambda . ,_)))
+     (macroexp--cons 'function
+                     (macroexp--cons (macroexp--all-forms f 2)
+                                     nil
+                                     (cdr form))
+                     form))
+    (`(,(or 'function 'quote) . ,_) form)
+    (`(,(and fun (or 'let 'let*)) . ,(or `(,bindings . ,body) dontcare))
+     (macroexp--cons fun
+                     (macroexp--cons (macroexp--all-clauses bindings 1)
+                                     (macroexp--all-forms body)
+                                     (cdr form))
+                     form))
+    (`(,(and fun `(lambda . ,_)) . ,args)
+     ;; Embedded lambda in function position.
+     (macroexp--cons (macroexp--all-forms fun 2)
+                     (macroexp--all-forms args)
+                     form))
+    ;; The following few cases are for normal function calls that
+    ;; are known to funcall one of their arguments.  The byte
+    ;; compiler has traditionally handled these functions specially
+    ;; by treating a lambda expression quoted by `quote' as if it
+    ;; were quoted by `function'.  We make the same transformation
+    ;; here, so that any code that cares about the difference will
+    ;; see the same transformation.
+    ;; First arg is a function:
+    (`(,(and fun (or 'funcall 'apply 'mapcar 'mapatoms 'mapconcat 'mapc))
+       ',(and f `(lambda . ,_)) . ,args)
+     (macroexp--warn-and-return
+      (format "%s quoted with ' rather than with #'"
+              (list 'lambda (nth 1 f) '...))
+      (macroexp--expand-all `(,fun ,f . ,args))))
+    ;; Second arg is a function:
+    (`(,(and fun (or 'sort)) ,arg1 ',(and f `(lambda . ,_)) . ,args)
+     (macroexp--warn-and-return
+      (format "%s quoted with ' rather than with #'"
+              (list 'lambda (nth 1 f) '...))
+      (macroexp--expand-all `(,fun ,arg1 ,f . ,args))))
+    (`(funcall #',(and f (pred symbolp)) . ,args)
+     ;; Rewrite (funcall #'foo bar) to (foo bar), in case `foo'
+     ;; has a compiler-macro.
+     (macroexp--expand-all `(,f . ,args)))
+    (`(,func . ,_)
+     ;; Macro expand compiler macros.  This cannot be delayed to
+     ;; byte-optimize-form because the output of the compiler-macro can
+     ;; use macros.
+     (let ((handler (function-get func 'compiler-macro)))
+       (if (null handler)
+           ;; No compiler macro.  We just expand each argument (for
+           ;; setq/setq-default this works alright because the variable names
+           ;; are symbols).
+           (macroexp--all-forms form 1)
+         ;; If the handler is not loaded yet, try (auto)loading the
+         ;; function itself, which may in turn load the handler.
+         (unless (functionp handler)
+           (with-demoted-errors "macroexp--expand-all: %S"
+             (autoload-do-load (indirect-function func) func)))
+         (if (eq handler 'internal--compiler-macro-cons*)
+             ;; The `cons*' compiler-macro generates very deep
+             ;; expansions, so macroexpand the arguments first to
+             ;; reduce the chance of exceeding recusion depth while
+             ;; macroexpanding.
+             (macroexp--compiler-macro handler (macroexp--all-forms form 1))
            (let ((newform (macroexp--compiler-macro handler form)))
              (if (eq form newform)
                  ;; The compiler macro did not find anything to do.
@@ -291,9 +290,9 @@ macroexp--expand-all
                    (if (eq newform form)
                        newform
                      (macroexp--expand-all newform)))
-               (macroexp--expand-all newform))))))
+               (macroexp--expand-all newform)))))))
 
-      (_ form))))
+    (_ form)))
 
 ;;;###autoload
 (defun macroexpand-all (form &optional environment)
diff --git a/lisp/subr.el b/lisp/subr.el
index c59f13b24c..c0b3c68229 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -577,6 +577,15 @@ cddddr
   (declare (compiler-macro internal--compiler-macro-cXXr))
   (cdr (cdr (cdr (cdr x)))))
 
+(defun internal--compiler-macro-cons* (_form arg &rest others)
+  (let* ((args (reverse (cons arg others)))
+         (form (car args)))
+    (while (setq args (cdr args))
+      (setq form `(cons ,(car args) ,form)))
+    form))
+
+(function-put 'cons* 'compiler-macro #'internal--compiler-macro-cons*)
+
 (defun last (list &optional n)
   "Return the last link of LIST.  Its car is the last element.
 If LIST is nil, return nil.
diff --git a/src/alloc.c b/src/alloc.c
index 64aaa8acdf..1fb7b1fc0b 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2699,6 +2699,18 @@ DEFUN ("list", Flist, Slist, 0, MANY, 0,
   return val;
 }
 
+DEFUN ("cons*", FconsX, SconsX, 1, MANY, 0,
+       doc: /* Like `list' but the last argument is the tail of the new list.
+(cons* A B C) is equivalent to (cons A (cons B C)).
+usage: (cons* FIRST &rest LIST)  */)
+  (ptrdiff_t nargs, Lisp_Object *args)
+{
+  Lisp_Object val = args[--nargs];
+
+  while (nargs > 0)
+    val = Fcons (args[--nargs], val);
+  return val;
+}
 
 DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
        doc: /* Return a newly created list of length LENGTH, with each element being INIT.  */)
@@ -7374,6 +7386,7 @@ syms_of_alloc (void)
 N should be nonnegative.  */);
 
   defsubr (&Scons);
+  defsubr (&SconsX);
   defsubr (&Slist);
   defsubr (&Svector);
   defsubr (&Srecord);
-- 
2.11.0


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

* bug#16963: A patch to create a list-with-tail primitive.
  2019-06-28  3:14     ` Noam Postavsky
@ 2019-06-28  3:30       ` Drew Adams
  0 siblings, 0 replies; 13+ messages in thread
From: Drew Adams @ 2019-06-28  3:30 UTC (permalink / raw)
  To: Noam Postavsky, Lars Ingebrigtsen; +Cc: 16963, Demetrios Obenour

> Oh, this reminds me I had started writing a patch for this.  I used the
> name cons* instead of list* though, I always found it more logical:
> cons* is cons repeated, just like let* is let repeated.  Let me dust it
> off:

The name has long been `list*' in Lisp, including
in Common Lisp.  That's the name that should (still)
be used, IMO.

http://clhs.lisp.se/Body/f_list_.htm

  list* is like list except that the last argument to list
  becomes the car of the last cons constructed, while the
  last argument to list* becomes the cdr of the last cons
  constructed. Hence, any given call to list* always
  produces one fewer conses than a call to list with the
  same number of arguments.

  If the last argument to list* is a list, the effect is
  to construct a new list which is similar, but which has
  additional elements added to the front corresponding to
  the preceding arguments of list*.

  If list* receives only one object, that object is returned,
  regardless of whether or not it is a list.





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

end of thread, other threads:[~2019-06-28  3:30 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-07 13:58 bug#16963: A patch to create a list-with-tail primitive Demetrios Obenour
2014-03-25  2:10 ` Stefan
2014-03-25  2:45   ` Daniel Colascione
2014-03-27 23:37     ` Demetrios Obenour
2014-03-27 23:38       ` Daniel Colascione
2014-03-28  0:43         ` Demetrios Obenour
2014-03-29  1:46         ` Demetrios Obenour
2014-03-29  1:48           ` Daniel Colascione
2014-03-29 13:30             ` Demetrios Obenour
2016-02-24  2:51 ` Lars Ingebrigtsen
2019-06-26 14:30   ` Lars Ingebrigtsen
2019-06-28  3:14     ` Noam Postavsky
2019-06-28  3:30       ` Drew Adams

Code repositories for project(s) associated with this public 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).