[Top][All Lists]

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

Re: emacs-lisp/cl.el (pushnew): void-variable x

From: Miles Bader
Subject: Re: emacs-lisp/cl.el (pushnew): void-variable x
Date: Tue, 12 Sep 2006 14:56:10 +0900

Stefan Monnier <address@hidden> writes:
> Honestly, I think using `add-to-list' here makes no sense.
> Since we have the variable as a symbol and we're macro-expanding, we can
> just use `(unless (member ,element ,var) (setq ,var (cons ,element ,var)))
> That'll be a lot more efficient than going through a function call to
> add-to-list, using an aux-var accessed via symbol-value and set and checking
> `append' arg etc...

Yup, and it even looks like cl-macs.el has the machinery in place to do
that, it's just very hard to follow (lots of levels of compiler-macros).

However I think it normally doesn't "take" because the default
comparison function for pushnew is `eql', not eq, so there's no non-cl
way to express the result; that's why it uses member*.

It works now to use: (pushnew a b :test 'eq), which expands at compile
time into the desired: (setq b (if (memq a b) b (cons a b))).

How about adding a new primitive `memql', a variant of memq that uses
eql -- which should be very efficient in C -- and then make the slight
tweak to cl's `member*' expander to produce that in the default case?

Then (pushnew a b) would expand to:

   (setq b (if (memql a b) b (cons a b))).

I think this is good behavior because most people probably want
more-or-less memq but don't want to uglify their code with the :test 'eq
grot; memql would be as fast as memq.

The following patche seems to implement this:

orig = address@hidden/emacs--miles--0--patch-27

M  lisp/emacs-lisp/cl-macs.el
M  lisp/subr.el

* modified files

--- orig/lisp/emacs-lisp/cl-macs.el
+++ mod/lisp/emacs-lisp/cl-macs.el
@@ -2578,21 +2578,7 @@
                   (cl-const-expr-val (nth 1 keys)))))
     (cond ((eq test 'eq) (list 'memq a list))
          ((eq test 'equal) (list 'member a list))
-         ((or (null keys) (eq test 'eql))
-          (if (eq (cl-const-expr-p a) t)
-              (list (if (floatp-safe (cl-const-expr-val a)) 'member 'memq)
-                    a list)
-            (if (eq (cl-const-expr-p list) t)
-                (let ((p (cl-const-expr-val list)) (mb nil) (mq nil))
-                  (if (not (cdr p))
-                      (and p (list 'eql a (list 'quote (car p))))
-                    (while p
-                      (if (floatp-safe (car p)) (setq mb t)
-                        (or (integerp (car p)) (symbolp (car p)) (setq mq t)))
-                      (setq p (cdr p)))
-                    (if (not mb) (list 'memq a list)
-                      (if (not mq) (list 'member a list) form))))
-              form)))
+         ((or (null keys) (eq test 'eql)) (list 'memql a list))
          (t form))))
 (define-compiler-macro assoc* (&whole form a list &rest keys)

--- orig/lisp/subr.el
+++ mod/lisp/subr.el
@@ -350,6 +350,15 @@
     (setq list (cdr list)))
+(defun memql (elt list)
+  "Like `memq', but compares numbers using `=' instead of `eq'."
+  (if (numberp elt)
+      (progn
+       (while (and list (not (eql elt (car list))))
+         (setq list (cdr list)))
+       list)
+    (memq elt list)))
 (defmacro with-lexical-binding (&rest body)
   "Execute the statements in BODY using lexical binding."
   `(let ((internal-interpreter-environment internal-interpreter-environment))


97% of everything is grunge

reply via email to

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