5

Clojure (1.4) は、ベクトルを同じベクトルの に等しいと喜んで考えているようですseqが、マップには同じことが当てはまらないことに気付きました。

(= [1 2] (seq [1 2]))
=> true

(= {1 2} (seq {1 2}))
=> false

の動作が=このように異なるのはなぜですか?

4

5 に答える 5

12

Clojureは、次の=2 つのステップで比較を実行すると考えることができます。

  1. 比較対象の型が同じ「等価パーティション」に属しているかどうかを確認します。これは、メンバーが潜在的に等しい可能性のある型のクラスです (特定のデータ構造の正確なメンバーなどによって異なりますが、特定の型ではありません)。パーティション);

  2. もしそうなら、比較されているものが実際に等しいかどうかを確認してください。

そのような等分割の 1 つは、「順次」のものの分割です。ベクトルは順次と見なされます。

(instance? clojure.lang.Sequential [])
;= true

さまざまなタイプの seq も同様です。

(instance? clojure.lang.Sequential (seq {1 2}))
;= true

したがって、対応する要素が等しい場合 (およびその場合にのみ)、ベクトルは seq と等しいと見なされます。

( は順次ではなく、「等しくない」を などと比較するを(seq {})生成することに注意してください。)nil()[]

一方、マップは独自の等価パーティションを構成するため、ハッシュ マップはソートされたマップと等しいと見なされる場合がありますが、seq と等しいとは見なされません。特に、エントリの seq と等しくないため、(seq some-map)生成されます。

于 2012-06-13T00:37:09.730 に答える
5

これは、シーケンスの順序と特定の位置の値が重要であるのに対し、マップではキー/値の順序は重要ではなく、このセマンティクスの違いにより、サンプルコードで示されているように機能するためだと思います。

詳細についてはmapEquals、ファイルhttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.javaを参照してください。

他のオブジェクトがマップされていないかどうかを確認し、false を返します。

于 2012-06-12T11:28:07.340 に答える
3
user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
于 2012-06-12T11:31:50.273 に答える
2

seqこの例は、(関数によって) 同じ型から派生した異なる型であるこの場合、clojure の値の等価性の概念にわずかな矛盾があることを指摘しているように思えます。派生型と派生元の型を比較しているため、これは矛盾していないと主張することもできます。ベクトルを使用してこの同じ例に同じロジックが適用された場合は理解できます (下部のメモ)。

内容は同じタイプです:

user> (type (first (seq {1 2})))
clojure.lang.MapEntry
user> (type (first {1 2}))
clojure.lang.MapEntry

user> (= (type (first {1 2})) (type (first (seq {1 2}))))
true
user> (= (first {1 2}) (first (seq {1 2})))
true

シーケンスは同じ値を持っています

user> (map = (seq {1 2}) {1 2})
(true)

user> (= {1 2} (seq {1 2})) false

これは、より長いマップにも当てはまります。

user> (map = (seq {1 2 3 4}) {1 2 3 4})
(true true)
user> (map = (seq {1 2 3 4 5 6}) {1 2 3 4 5 6})
(true true true)
user> (map = (seq {9 10 1 2 3 4 5 6}) {9 10 1 2 3 4 5 6})
(true true true true)    

それらが同じ順序でなくても:

user> (map = (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
(true true true true)

しかし、含まれている型が異なる場合はそうではありません:-(

user> (= {1 2 3 4} (seq {1 2 3 4}))
false

編集: これは常に真であるとは限りません。以下を参照してください: これを回避するには、比較の前にすべてを seq に変換できます。これは、seq 関数が常に同じ方法でデータ構造全体を反復し、構造が不変の値であるため (推定) 安全です。そして aseqの aseqは aseq

user> (= (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
false
user> (= (seq {9 10 1 2 3 4 5 6}) (seq {1 2 3 4 5 6 9 10}))
true


ベクトルの扱いは異なります。

user> (= [1 2 3 4] (seq [1 2 3 4]))
true

おそらく、マイナーな矛盾を理解することは言語を学ぶことの一部であるか、またはいつかこれを変更できる可能性があります(私は息を止めませんが)


編集:

同じ値に対して異なるシーケンスを生成する 2 つのマップを見つけたので、マップで seq を呼び出すだけでは適切なマップの等価性が得られません。

user> (seq (zipmap  [3 1 5 9][4 2 6 10]))
([9 10] [5 6] [1 2] [3 4])
user> (seq {9 10 5 6 1 2 3 4})
([1 2] [3 4] [5 6] [9 10])
user> 

これが私が適切なマップの等価性と呼んでいるものの例です:

user> (def a (zipmap  [3 1 5 9][4 2 6 10]))
#'user/a
user> (def b {9 10 5 6 1 2 3 4})
#'user/b
user> (every? true? (map #(= (a %) (b %)) (keys a)))
true
于 2012-06-12T17:18:39.813 に答える
1

(seq some-hash-map)一連のエントリ (キーと値のペア) を提供します。

例えば:

foo.core=> (seq {:a 1 :b 2 :c 3})
([:a 1] [:c 3] [:b 2])

と同じではありません[:a 1 :b 2 :c 3]

于 2012-06-13T14:32:16.470 に答える