[alexandria-devel] cdr assoc (now called alist-get)

John Fremlin john at fremlin.org
Tue Feb 10 05:02:32 UTC 2009


For http://common-lisp.net/project/cl-irregsexp/ and in fact for many 
other projects, it is quite handy to have a way of storing key value 
pairs in a table that is more lightweight than a hashtable, and that 
preserves ordering.

The obvious way to do it in Lisp is to store a list like '((key0 . 
value0) (key1 . value1) ...)

However in the ANSI standard there is no easy way to implement (setf 
(gethash key table) value).

(cdr (assoc ...)) is sufficient for lookup.

To that end there is commonly available in extensions a (setf 
cdr-assoc). I posted one to the list before but I had managed to mangle 
it utterly in my last edit of it and it didn't work.

I hope that was why you Alexandrians ignored me . . .

Anyway, one problem with cdr-assoc is that the order of parameters is 
apparently non-standard. To alleviate this problem I have come back with 
a new name, alist-get and also ralist-get (for cdr-rassoc, the 
(value.key) convention).

Feedback very much appreciated!



(declaim (inline racons))
(defun racons (key value ralist)
   (acons value key ralist))


(macrolet ((define-alist-get (name get-pair get-value-from-pair add)
	     `(progn
		(declaim (inline ,name))
		(defun ,name (alist key &key (test 'eql))
		  (let ((pair (,get-pair key alist :test test)))
		    (values (,get-value-from-pair pair) pair)))
		(define-setf-expander ,name (place key &key (test ''eql)
					     &environment env)
		  (multiple-value-bind (dummies vals newvals setter getter)
		      (get-setf-expansion place env)
		    (when (cdr newvals)
		      (error "~A cannot store multiple values in one place" ',name))
		    (with-unique-names (store key-val test-val alist found)
		      (values
		       `(, at dummies ,key-val ,test-val)
		       `(, at vals ,key ,test)
		       (list store)
		       `(let ((,alist ,getter))
			  (let ((,found (,',get-pair ,key-val ,alist :test ,test-val)))
			    (cond (,found
				   (setf (,',get-value-from-pair ,found) ,store))
				  (t
				   (let ,newvals
				     (setf ,(first newvals) (,',add ,key ,store ,alist))
				     ,setter)))
			    ,store))
		       `(,',name ,getter ,key))))))))
   (define-alist-get alist-get assoc cdr acons)
   (define-alist-get ralist-get rassoc car racons))




More information about the alexandria-devel mailing list