2015-11-20 11 views
6

Mam następujące klasy:Używanie wystąpień klasy CLOS jako kluczy tabeli mieszającej?

(defclass category() 
    ((cat-channel-name 
    :accessor cat-channel-name :initarg :cat-channel-name :initform "" :type string 
    :documentation "Name of the channel of this category") 
    (cat-min 
    :accessor cat-min :initarg :min :initform 0 :type number 
    :documentation "Mininum value of category") 
    (cat-max 
    :accessor cat-max :initarg :max :initform 1 :type number 
    :documentation "Maximum value of category")) 
    (:documentation "A category")) 

Teraz chciałbym użyć tej klasy jako klucz dla hash-table. Adresy instancji można łatwo porównać z eq. Problem jednak może być związany z wieloma identycznymi instancjami klasy category i chciałbym, aby tablica mieszająca również rozpoznała to jako klucz.

Tak, starałem się zastąpić :test argument funkcji make-hash-table tak:

(make-hash-table :test #'(lambda (a b) (and (equal (cat-channel-name a) (cat-channel-name b)) 
              (eq (cat-min a) (cat-min b)) 
              (eq (cat-max a) (cat-max b))) 

Niestety, nie jest to dozwolone. :test musi być oznacznikiem jednej z funkcji: eq, eql, equal lub equalp.

Jednym ze sposobów rozwiązania tego problemu byłoby przekształcenie klasy category w strukturę, ale potrzebuję tego, aby była klasą. Czy istnieje sposób, w jaki mogę to rozwiązać?

+0

Dlaczego jest to klasa? – coredump

+0

Czy chcesz użyć * wystąpień * jako kluczy lub samej klasy? –

Odpowiedz

6

można użyć bardziej rozszerzalny biblioteki tablicy mieszającej, jak wyjaśniono w odpowiedzi Coredump, ale można również użyć podejścia Common Lisp trwa ku symboli: można intern im. W takim przypadku potrzebna jest odpowiednia funkcja interningu, która zajmuje wystarczającą ilość kategorii, aby utworzyć instancję kanoniczną, oraz tablicę haszującą, w której będą przechowywane. Na przykład.Z uproszczonej kategoria Klasa:

(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)))))) 

Następnie można nazwać intern-kategorię z tymi samymi argumentami i dostać samo obiektu tyłu, które można bezpiecznie używać jako klucz tabeli hash:

(eq (intern-category "foo" 45) 
    (intern-category "foo" 45)) 
;=> T 
+0

Będę pamiętać o tym, miłe podejście. – coredump

+0

Myślę, że to jest eleganckie rozwiązanie mojego problemu. Dzięki! – JNevens

+0

To tak naprawdę nie odpowiada na pytanie. Pokazuje tylko, że możesz odwzorować szczeliny na consy, które mogą mieć gracze w tabelach mieszania 'equalp'. Ale domyślam się, że ** op ** zdaje sobie z tego sprawę, wspominając o użyciu struktur, które mogą również grokować w tabelach hash "equalp'". – acelent

6
  1. Nie porównuj numery z eq, użyj eql lub =. Od eq (podkreślenie moje):

    Obiekty, które wyglądają tak samo po wydrukowaniu, niekoniecznie odpowiadają sobie nawzajem. [...] W dowolnym momencie możliwe jest wykonanie "kopii" znaków i cyfr. Efekt jest taki, że Common Lisp sprawia, że ​​nie gwarantuje, że eq jest prawdziwe, nawet jeśli oba argumenty są "to samo", jeśli jest to znak lub numer.

  2. Można użyć biblioteki genhash. Po pierwsze, należy zdefiniować nową funkcję skrótu (patrz również sxhash) i funkcja testu dla danego typu i powiązać go z desygnatora testowym:

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

    Następnie można zdefiniować nową tabelę:

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

Wiele implementacji Common Lisp zapewnić rozszerzeń standardu ANSI Common Lisp, aby obsługiwać różne funkcje testowe i hash (i dużo więcej).

CL-CUSTOM-HASH-TABLE to warstwa kompatybilności.

Powiązane problemy