7

私は次のクラスを持っています:

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

ここで、このクラスをハッシュ テーブルのキーとして使用したいと思います。インスタンスのアドレスは、 と簡単に比較できますeq。ただし、問題は、このcategoryクラスの同一のインスタンスが複数存在する可能性があることです。ハッシュ テーブルにこれもキーとして認識させたいと考えています。

だから、私はこのように関数の:test引数を上書きしようとしていました:make-hash-table

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

残念ながら、これは許可されていません。:test関数 eq、eql、equal、または equalp のいずれかの指定子である必要があります。

これを解決する 1 つの方法は、クラスcategoryを構造体に変換することですが、クラスにする必要があります。これを解決する方法はありますか?

4

3 に答える 3

7

多くの Common Lisp 実装は、ANSI Common Lisp 標準への拡張機能を提供して、さまざまなテスト関数とハッシュ関数 (およびそれ以上) をサポートします。

CL-CUSTOM-HASH-TABLEは互換性レイヤーです。

于 2015-11-20T17:34:18.337 に答える
6

コアダンプの回答で説明されているように、より拡張可能なハッシュ テーブル ライブラリを使用できますが、Common Lisp がシンボルに対して採用するアプローチを使用することもできます。それらをインターンできます。この場合、正規のインスタンスを生成するのに十分なカテゴリを取得する適切なインターニング関数と、それらを格納するためのハッシュ テーブルが必要です。たとえば、単純化されたカテゴリクラスを使用すると、次のようになります。

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

次に、同じ引数でintern-categoryを呼び出し、同じオブジェクトを取得して、ハッシュ テーブル キーとして安全に使用できます。

(eq (intern-category "foo" 45)
    (intern-category "foo" 45))
;=> T
于 2015-11-20T16:20:55.900 に答える
6
  1. 、またはeqを使用して数値を比較しないでください。から(強調鉱山):eql=eq

    印刷されたときに同じように見えるオブジェクトは、必ずしも互いに同等であるとは限りません。[...] 実装では、いつでも文字と数字の「コピー」を作成できます。その結果、Common Lisp は、両方の引数が「同じもの」であっても、それが文字または数値である場合でも、 eq が真であることを保証しません

  2. 図書館を利用できますgenhash。最初に、新しいハッシュ関数 ( も参照) と型のテスト関数を定義し、それをテスト指示子sxhashに関連付けます。

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

    次に、新しいテーブルを定義できます。

    (genhash:make-generic-hashtable :test 'category=)
    
于 2015-11-20T14:30:40.237 に答える