Clojure (1.4) は、ベクトルを同じベクトルの に等しいと喜んで考えているようですseq
が、マップには同じことが当てはまらないことに気付きました。
(= [1 2] (seq [1 2]))
=> true
(= {1 2} (seq {1 2}))
=> false
の動作が=
このように異なるのはなぜですか?
Clojureは、次の=
2 つのステップで比較を実行すると考えることができます。
比較対象の型が同じ「等価パーティション」に属しているかどうかを確認します。これは、メンバーが潜在的に等しい可能性のある型のクラスです (特定のデータ構造の正確なメンバーなどによって異なりますが、特定の型ではありません)。パーティション);
もしそうなら、比較されているものが実際に等しいかどうかを確認してください。
そのような等分割の 1 つは、「順次」のものの分割です。ベクトルは順次と見なされます。
(instance? clojure.lang.Sequential [])
;= true
さまざまなタイプの seq も同様です。
(instance? clojure.lang.Sequential (seq {1 2}))
;= true
したがって、対応する要素が等しい場合 (およびその場合にのみ)、ベクトルは seq と等しいと見なされます。
( は順次ではなく、「等しくない」を などと比較するを(seq {})
生成することに注意してください。)nil
()
[]
一方、マップは独自の等価パーティションを構成するため、ハッシュ マップはソートされたマップと等しいと見なされる場合がありますが、seq と等しいとは見なされません。特に、エントリの seq と等しくないため、(seq some-map)
生成されます。
これは、シーケンスの順序と特定の位置の値が重要であるのに対し、マップではキー/値の順序は重要ではなく、このセマンティクスの違いにより、サンプルコードで示されているように機能するためだと思います。
詳細についてはmapEquals
、ファイルhttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.javaを参照してください。
他のオブジェクトがマップされていないかどうかを確認し、false を返します。
user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
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
(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]
。