Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure equality of collections with sequences

I noticed that Clojure (1.4) seems to be happy to consider vectors equal to the seq of the same vector, but that the same does not apply for maps:

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

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

Why should the behaviour of = be different in this way?

like image 874
mikera Avatar asked Jun 12 '12 11:06

mikera


People also ask

How do you check for equality in Clojure?

Equality in Clojure is most often tested using = . Unlike Java's equals method, Clojure's = returns true for many values that do not have the same type as each other. = does not always return true when two numbers have the same numeric value.

What is seq Clojure?

A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences. The seq function yields an implementation of ISeq appropriate to the collection.

What is a collection in Clojure?

Clojure collections "collect" values into compound values. There are four key Clojure collection types: vectors, lists, sets, and maps. Of those four collection types, vectors and lists are ordered.

What is vector Clojure?

A Vector is a collection of values indexed by contiguous integers. A vector is created by using the vector method in Clojure.


3 Answers

Clojure's = can be thought of as performing its comparisons in two steps:

  1. Check if the types of the things being compared belong to the same "equality partition", that is a class of types whose members might potentially be equal (depending on things like the exact members of a given data structure, but not the particular type in the partition);

  2. If so, check if the things being compared actually are equal.

One such equality partition is that of "sequential" things. Vectors are considered sequential:

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

As are seqs of various types:

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

Therefore a vector is considered equal to a seq if (and only if) their corresponding elements are equal.

(Note that (seq {}) produces nil, which is not sequential and compares "not equal" to (), [] etc.)

On the other hand, maps constitute an equality partition of their own, so while a hash map might be considered equal to a sorted map, it will never be considered equal to a seq. In particular, it is not equal to the seq of its entries, which is what (seq some-map) produces.

like image 190
Michał Marczyk Avatar answered Oct 06 '22 08:10

Michał Marczyk


I guess this is because in sequences order as well as value at particular position matters where as in map the order of key/value doesn't matter and this difference between semantics causes this to work as shown by your sample code.

For more details have a look at mapEquals in file https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java

It checks if the other object is not map then return false.

like image 32
Ankur Avatar answered Oct 06 '22 10:10

Ankur


user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
like image 3
number23_cn Avatar answered Oct 06 '22 08:10

number23_cn