In the spirit of `14.1.2.2 Lists as Sets', that is, in order to facilitate use of hash tables as sets, it seems to make sense to extend MAPHASH-KEYS and MAPHASH-VALUES to accept :TEST, :TEST-NOT and :KEY, as specified by `17.2.1 Satisfying a Two-Argument Test', with a difference of making tests accept a single parameter.
A possible implementation (derived from SBCL sources) is as follows:
(defmacro apply-key (key element) `(if ,key (funcall ,key ,element) ,element))
(defmacro satisfies-the-test (elt) (with-gensyms (key-tmp) `(let ((,key-tmp (apply-key key ,elt))) (cond (testp (funcall test ,key-tmp)) (notp (not (funcall test-not ,key-tmp))) (t t)))))
(declaim (inline maphash-keys)) (defun maphash-keys (function table &key key (test nil testp) (test-not nil notp)) "Like MAPHASH, but calls FUNCTION with each key in the hash table TABLE." (when (and testp notp) (error ":TEST and :TEST-NOT were both supplied.")) (maphash (lambda (k v) (declare (ignore v)) (when (satisfies-the-test k) (funcall function k))) table))
(declaim (inline maphash-values)) (defun maphash-values (function table &key key (test nil testp) (test-not nil notp)) "Like MAPHASH, but calls FUNCTION with each value in the hash table TABLE." (when (and testp notp) (error ":TEST and :TEST-NOT were both supplied.")) (maphash (lambda (k v) (declare (ignore k)) (when (satisfies-the-test k) (funcall function v))) table))
There is also a question of whether it is desirable to extend in a similar manner MAPHASH itself (under a different name), so as to make it accept :KEY-KEY, :VALUE-KEY, :KEY-TEST, :VALUE-TEST, which would make the extension protocol usable in a wider range of scenarios.
regards, Samium Gromoff
alexandria-devel@common-lisp.net