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 `(,@dummies ,key-val ,test-val) `(,@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))
John Fremlin john@fremlin.org writes:
I hope that was why you Alexandrians ignored me . . .
No ignoring, it's just the wrong phase of the moon right now.
-T.
Dear Alexandrians,
"Tobias C. Rittweiler" tcr@freebits.de writes:
I hope that was why you Alexandrians ignored me . . .
No ignoring, it's just the wrong phase of the moon right now.
Please consider the cdr-assoc again. It could be improved, which improvements would encourage you to view it more favourably?
It is pretty useful to be able to use alists as an alternative to a small hash table.
(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 (append dummies (list key-val test-val)) (append vals (list 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))
[...]
John Fremlin john@fremlin.org writes:
Dear Alexandrians,
"Tobias C. Rittweiler" tcr@freebits.de writes:
I hope that was why you Alexandrians ignored me . . .
No ignoring, it's just the wrong phase of the moon right now.
Please consider the cdr-assoc again. It could be improved, which improvements would encourage you to view it more favourably?
It is pretty useful to be able to use alists as an alternative to a small hash table.
I agree. I personally don't like the two proposed names, though:
CDR-ASSOC, ALIST-GET
Others I've come up with are
ALIST-REF, GETA
my personal favorite would be
ASSOC-VALUE
-T.
"Tobias C. Rittweiler" tcr@freebits.de writes:
my personal favorite would be
ASSOC-VALUE
Or perhaps GETASSOC imitating GETHASH.
-T.
"Tobias C. Rittweiler" tcr@freebits.de writes:
"Tobias C. Rittweiler" tcr@freebits.de writes:
my personal favorite would be
ASSOC-VALUE
Or perhaps GETASSOC imitating GETHASH.
Certainly a better way of dealing with alists would be useful.
cdr-assoc is the customary name for this functionality.
The problem is with the order of parameters: alist and key. As far as I know, cdr-assoc has been implemented both as taking the key first and as taking the alist first. That's why I wanted a new name.
At least, getassoc (and presumably getrassoc) would clearly indicate key first, by analogy with gethash.
I think that is sensible . . . I can send a new patch with the new names if you like.
(If alexandria wakes up then I have a patch to fix some other stuff too.)
(If alexandria wakes up then I have a patch to fix some other stuff too.)
it's awake, but things here work based on consensus, so no one is hasty of pushing new stuff.
so, please do send whatever you have! i, and many others, mark mails with pending patches and eventually get to it.
as of this thread, i've recorded the code found in your latest mail and pushed it to the repo using the names: - assoc-value - rassoc-value
i've kept them in the experimental part of package.lisp for now.
please feel free to make further changes to the repo and/or write up suggestions here (especially about its name if there's any objection)!
thanks,
alexandria-devel@common-lisp.net