我注意到Clojure(1.4)似乎很乐意考虑等于同一向量的seq
的向量,但这同样不适用于地图:
(= [1 2] (seq [1 2]))
=> true
(= {1 2} (seq {1 2}))
=> false
为什么=
的行为会以这种方式不同?
答案 0 :(得分:12)
Clojure的=
可以被认为是通过两个步骤进行比较:
检查被比较的东西的类型是否属于相同的“相等分区”,即一类类型的成员可能相等(取决于给定数据结构的确切成员之类的东西,但不是分区中的特定类型);
如果是,请检查实际比较的内容是否相等。
一个这样的平等分区是“顺序”事物。向量被认为是顺序的:
(instance? clojure.lang.Sequential [])
;= true
与各种类型的seqs一样:
(instance? clojure.lang.Sequential (seq {1 2}))
;= true
因此,如果(并且仅当)它们的相应元素相等,则认为向量等于seq。
(请注意,(seq {})
生成nil
,不顺序,并将“不等于”与()
,[]
等进行比较。)
另一方面,映射构成了它们自己的相等分区,因此虽然哈希映射可能被认为等于有序映射,但它永远不会被认为等于seq。特别是,它不等于其条目的seq,这是(seq some-map)
产生的。
答案 1 :(得分:5)
我想这是因为序列顺序以及特定位置的值很重要,因为在映射中键/值的顺序无关紧要,语义之间的这种差异会导致它按照示例代码所示工作。 / p>
有关详细信息,请查看文件https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java
中的mapEquals
它检查另一个对象是否不是map,然后返回false。
答案 2 :(得分:3)
user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
答案 3 :(得分:2)
在我看来,这个例子指出了clojure中值的相等概念在这种情况下略有不一致,在这种情况下,它们是从相同类型派生的不同类型(通过seq
函数)。可以说这不是不一致的,因为它是将派生类型与它派生的类型进行比较,我可以理解,如果使用向量将相同的逻辑应用于同一个例子(注意在底部)
内容属于同一类型:
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)
但他们并不被认为是平等的 使用者名称> (= {1 2}(seq {1 2})) 假
对于较长的地图也是如此:
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函数总是以相同的方式迭代整个数据结构,结构是不可变的值和{ seq
{1}}是seq
seq
<小时/> 向量的处理方式不同:
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
也许理解微小的不一致是学习语言的一部分,或者有一天可以改变(虽然我不会屏住呼吸)
<小时/> 编辑:
我发现两个地图为相同的值生成不同的序列,所以只是在地图上调用seq不会给你正确的地图相等:
user> (= [1 2 3 4] (seq [1 2 3 4]))
true
这是我称之为正确的地图平等的一个例子:
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>
答案 4 :(得分: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]
不同。