redefining memq, was CVS: maxima...



There were typos previously. A correct alternative definition of memq would
be 
(defun memq(a  b)(declare(optimize (speed 3)(safety 0)))
       (or (and b (eq a (car b)) b)
	   (and (cdr b)(eq a (cadr b)) (cdr b))
	   (and (cddr b)(eq a (caddr b)) (cddr b))
	   (member a (cdddr b) :test #'eq)))

 but that still has a function call.
a macro definition would look like

(defmacro memq(ax bx)(let((a (gensym))(b (gensym))) ;evaluate ax, bx just
once
		    `(let((,a ,ax)(,b ,bx))
		           (or (and ,b (eq ,a (car ,b)) ,b)
			       (and (cdr ,b)(eq ,a (cadr ,b)) (cdr ,b))
			       (and (cddr ,b)(eq ,a (caddr ,b)) (cddr ,b))
			       (member ,a (cdddr ,b) :test #'eq)))))


and yes, in my testing, it is faster.

If a  is the first item, it is 6X faster than member, if a is the second
item, about 2.5 times faster, and if a is the third item, about 1.7 times
faster. If b is 3 elements and a is not there at all, it is 1.7 times
faster.

If b is 2 elements and a is not there, it is about 1.7 times faster.


I suggest that this redefinition of memq is sufficiently superior that all
those places where you put member and where memq was, should be changed back
to memq unless you can seriously convince youself that the list b is longer
than 3, and that the element a is rarely in the first 3 elements of b.

of course your lisp may be different (I'm using allegro common lisp);  CLISP
in particular may differ.
In general, any attempt to time such a fast function will require looping
over many iterations, e.g. 100,000,000.
So be sure to subtract off the time for the looping construct.

Cheers.
RJF