2014-10-29 103 views
4

如果我有一个自定义类型,并使用它创建具有完全相同值的两个单独实例,那么可以使用什么方法来确定这两个事物是等价的? identical?===似乎不起作用。我预料会有一些协议来设置类型比较。最终,我希望它能够将相同的事物添加到一个集合中。Clojure值相等并设置

(deftype Ref [id]) 
(def r1 (->Ref 1)) 
(def r2 (->Ref 1)) 
(= r1 r2) ;false rather than true 
(def refs #{}) 
(conj refs r1 r2) ;adds both, but want one 

=作品与defrecord,但我会如何定义=deftype

+1

一件小事:'=='仅为数字数据定义'user>(==:a:a)=> ClassCastException clojure.lang.Keyword不能转换为java.lang.Number clojure.lang.Numbers .equiv(Numbers.java:206)' – noisesmith 2014-10-29 04:45:55

回答

4

defrecord已经有这种行为你描述:

user=> (defrecord Point [x y]) 
user.Point 
user=> (= (Point. 0 0) (Point. 0 0)) 
true 
user=> (into #{} [(Point. 0 0) (Point. 1 1) (Point. 0 0)]) 
#{#user.Point{:x 1, :y 1} #user.Point{:x 0, :y 0}} 

deftype,另一方面不执行默认Clojure的常用结构相等(也不是defstruct为我们提供了可读取的打印方法):

user=> (deftype Pair [a b]) 
user.Pair 
user=> (= (Pair. 0 0) (Pair. 0 0)) 
false 
user=> (into #{} [(Pair. 0 0) (Pair. 1 1) (Pair. 0 0)]) 
#{#<Pair [email protected]> #<Pair [email protected]> #<Pair [email protected]>} 

也就是说,deftype功能更强大,您可以使其表现得像我们喜欢的:

user=> (deftype Tuple [a b] 
     Object 
     (equals [this other] 
      (and (= (.a this) (.a other)) 
       (= (.b this) (.b other)))) 
     (toString [this] 
      (str "<" (.a this) "," (.b this) ">")) 
     (hashCode [this] 
      (hash {:a (.a this) :b (.b this)})) 
     Comparable 
     (compareTo [this that] 
      (compare [(.a this) (.b this)] 
        [(.a that) (.b that)]))) 
user.Tuple 
user=> (= (Tuple. 0 0) (Tuple. 0 0)) 
true 
user=> (into #{} [(Tuple. 0 0) (Tuple. 1 1) (Tuple. 0 0)]) 
#{#<Tuple <0,0>> #<Tuple <1,1>>} 
6

在你DEFTYPE,延长Object和实施equals给他们平等的语义:

(deftype Ref [id] 
    Object 
    (equals [_ other] (= id (.id other)))) 

集遏制,还需要哈希码支持:

(deftype Ref [id] 
    Object 
    (equals [_ other] (= id (.id other))) 
    (hashCode [_] id) 
    clojure.lang.IHashEq 
    (hasheq [_] id)) 

我实现了两个Java的哈希支持和Clojure的hasheq在那里支持。实施IHashEq会更快。

+0

'hash-set',等于不足(我试过了),'hashCode'也是需要的。还没有完成 – noisesmith 2014-10-29 04:37:16

+0

输入...现在:) – 2014-10-29 04:46:19