Using CLOS class instances as hash-table keys?

放肆的年华 提交于 2019-12-05 07:11:42

You can use a more extensible hash table library, as explained in coredump's answer, but you could also use the approach that Common Lisp takes toward symbols: you can intern them. In this case, you just need an appropriate interning function that takes enough of a category to produce a canonical instance, and a hash table to store them. E.g., with a simplified category class:

(defclass category ()
  ((name :accessor cat-name :initarg :name)
   (number :accessor cat-number :initarg :number)))

(defparameter *categories*
  (make-hash-table :test 'equalp))

(defun intern-category (name number)
  (let ((key (list name number)))
    (multiple-value-bind (category presentp)
        (gethash key *categories*)
      (if presentp category
          (setf (gethash key *categories*)
                (make-instance 'category
                               :name name
                               :number number))))))

Then, you can call intern-category with the same arguments and get the same object back, which you can safely use as a hash table key:

(eq (intern-category "foo" 45)
    (intern-category "foo" 45))
;=> T
  1. Don't compare numbers with eq, use eql or =. From eq (emphasis mine):

    Objects that appear the same when printed are not necessarily eq to each other. [...] An implementation is permitted to make "copies" of characters and numbers at any time. The effect is that Common Lisp makes no guarantee that eq is true even when both its arguments are "the same thing" if that thing is a character or number.

  2. You can use the genhash library. First, you define a new hash function (see also sxhash) and a test function for your type and you associate it with a test designator:

    (genhash:register-test-designator
      'category= 
      (lambda (category) <hashing>)
      (lambda (a b) 
        (and (equal ... ...)
             (= ... ...)
             (= ... ...))))
    

    Then, you can define a new table:

    (genhash:make-generic-hashtable :test 'category=)
    

Many Common Lisp implementations provide extensions to the ANSI Common Lisp standard to support different test and hash functions (and a lot more).

CL-CUSTOM-HASH-TABLE is a compatibility layer.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!