Meaning of "="

290 views
Skip to first unread message

Larry Travis

unread,
Oct 3, 2012, 1:24:22 AM10/3/12
to clo...@googlegroups.com, Larry Travis
What is the rationale for this?

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

I was quite surprised when this turned out to be the cause of a bug in a
function I am constructing. Vectors and lists differ so substantially in
their implementation and in their behavior that a vector and a list
should not be considered "equal" just because they contain the same
elements in the same order.

--Larry


Mark Engelberg

unread,
Oct 3, 2012, 4:44:31 AM10/3/12
to clo...@googlegroups.com
It is surprising at first, but since vectors are used so commonly in Clojure instead of lists to represent literal sequential collections of data, it turns out to be extremely convenient to be able to compare it for equality against sequential collections generated as lists or lazy sequences.  Basically, all those things are just flat, linear collections, and what we really care about from an equality standpoint is whether the collections have the same elements in the same order.  Clojure similarly considers different types of maps (hash-maps, array-maps, sorted-maps) to be equal if the associations are the same.  Ditto for hash-sets and sorted-sets.



  --Larry


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Grant Rettke

unread,
Oct 3, 2012, 11:43:17 AM10/3/12
to clo...@googlegroups.com
The Joy of Clojure book touches on this, it is an important design and
style decision. Great book, good question too. I'm learning about all
this stuff right now and it is all good stuff.
>> clojure+u...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en



--
((λ (x) (x x)) (λ (x) (x x)))
http://www.wisdomandwonder.com/
ACM, AMA, COG, IEEE

Warren Lynn

unread,
Oct 3, 2012, 1:56:18 PM10/3/12
to clo...@googlegroups.com


On Wednesday, October 3, 2012 4:44:44 AM UTC-4, puzzler wrote:
It is surprising at first, but since vectors are used so commonly in Clojure instead of lists to represent literal sequential collections of data, it turns out to be extremely convenient to be able to compare it for equality against sequential collections generated as lists or lazy sequences.  Basically, all those things are just flat, linear collections, and what we really care about from an equality standpoint is whether the collections have the same elements in the same order.  Clojure similarly considers different types of maps (hash-maps, array-maps, sorted-maps) to be equal if the associations are the same.  Ditto for hash-sets and sorted-sets.



Out of curiosity, if we want to check if two collections has the same structure/type and elements, namely if I want
(my-equal  [1 2 3 4 '(5)]  [1 2 3 4 [5]]) => false
(my-equal  [1 2 3 4 [5]]  [1 2 3 4 [5]]) => true

Is there any convenient way to do that? Thank you.

Timothy Baldridge

unread,
Oct 3, 2012, 3:04:02 PM10/3/12
to clo...@googlegroups.com

It is surprising at first, but since vectors are used so commonly in Clojure instead of lists to represent literal sequential collections of data, it turns out to be extremely convenient to be able to compare it for equality against sequential collections generated as lists or lazy sequences.  Basically, all those things are just flat, linear collections, and what we really care about from an equality standpoint is whether the collections have the same elements in the same order.  Clojure similarly considers different types of maps (hash-maps, array-maps, sorted-maps) to be equal if the associations are the same.  Ditto for hash-sets and sorted-sets.



This comes in handy once you realize that the core functions will sometimes return different types than you expected:

user=> (type (range 4))
clojure.lang.LazySeq

user=> (reduce conj clojure.lang.PersistentQueue/EMPTY [0 1 2 3])
#<PersistentQueue clojure.lang.PersistentQueue@e44e33f5>

user=> (type '(0 1 2 3))
clojure.lang.PersistentList

user=> (type (subvec [0 1 2 3 4 5] 0 4))
clojure.lang.APersistentVector$SubVector

user=> (type (vals {1 1 2 2 3 3 4 4}))
clojure.lang.APersistentMap$ValSeq

Putting it all together:

user => (=  (reduce conj clojure.lang.PersistentQueue/EMPTY [0 1 2 3])
                 (range 4)
                 '(0 1 2 3)
                 (subvec [0 1 2 3 4 5] 0 4)
                 (vals {0 0 1 1 2 2 3 3}))

true

That right there is real power my friends.

Timothy

Stuart Sierra

unread,
Oct 5, 2012, 4:48:35 PM10/5/12
to clo...@googlegroups.com
On Wednesday, October 3, 2012 1:56:19 PM UTC-4, Warren Lynn wrote:
Out of curiosity, if we want to check if two collections has the same structure/type and elements, namely if I want
(my-equal  [1 2 3 4 '(5)]  [1 2 3 4 [5]]) => false
(my-equal  [1 2 3 4 [5]]  [1 2 3 4 [5]]) => true

Is there any convenient way to do that?

Not really. You would have to define your own equality function. Then you have to make all the decisions about what should be considered "equal." For example, lists versus sequences, hash-maps versus array-maps.

-S

Jim foo.bar

unread,
Dec 11, 2012, 8:17:40 AM12/11/12
to clo...@googlegroups.com
I disagree...
One of the nice things about clojrue is that, at tis hear, lies the
'equiv' operator which is basically the 'egal' fn as defined by Baker
[1993] [Equal rights for functional objects or the mroe things change
the more they stay the same]. When using '=' with data-structures you
are essentially comparing values and not types.

To come back to your example, both are sequential seqs that contain the
same values in the same order. Why shouldn't they be equal? Clojure
would not be the language we all love, if they weren't equal...

Jim

Jim foo.bar

unread,
Dec 11, 2012, 8:19:48 AM12/11/12
to clo...@googlegroups.com
From the docs:

Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison.

hope that helps...

Jim

Jim foo.bar

unread,
Dec 11, 2012, 8:32:06 AM12/11/12
to clo...@googlegroups.com
If you're looking for some truly unintuitive  equality behavior check this out:

user=> (def pred (Boolean. false)) ;;not a primitive but an object
#'user/pred
user=> (= pred false)
true
user=> (when pred (println "I really shouldn't print"))
I really shouldn't print
nil


Jim

Jim foo.bar

unread,
Dec 11, 2012, 8:38:20 AM12/11/12
to clo...@googlegroups.com
Apologies...I did not realise this had already been answered... oops! :-)

Nathan Matthews

unread,
Dec 11, 2012, 9:56:32 AM12/11/12
to clo...@googlegroups.com, clo...@googlegroups.com
For more "surprising" behaviour:

(= #".*" #".*")



Sent from my iPhone

Andy Fingerhut

unread,
Dec 11, 2012, 1:03:12 PM12/11/12
to clo...@googlegroups.com
I added some text to the macro "if" on ClojureDocs.org last time this issue was discussed on the email list.  It is a bit wordy, but does also mention that this is something the Java docs themselves warn about.


Andy

Phil Hagelberg

unread,
Dec 11, 2012, 6:30:26 PM12/11/12
to clo...@googlegroups.com
On Tue, Dec 11, 2012 at 5:17 AM, Jim foo.bar <jimpi...@gmail.com> wrote:
> I disagree...
> One of the nice things about clojrue is that, at tis hear, lies the 'equiv'
> operator which is basically the 'egal' fn as defined by Baker [1993] [Equal
> rights for functional objects or the mroe things change the more they stay
> the same]. When using '=' with data-structures you are essentially comparing
> values and not types.
>
> To come back to your example, both are sequential seqs that contain the same
> values in the same order. Why shouldn't they be equal?

It's interesting that you quote Baker, because this is one of the
places where Clojure explicitly cheats and ignores Baker's operational
equivalence in favour of convenience. Egal's operational equivalence
would not treat lists and vectors as equivalent because they have very
different behaviour characteristics when it comes to conj, etc, but if
Clojure treated them differently then laziness would be much more
burdensome.

There are a few other places where Clojure cheats too, but this is the
most noticeable.

-Phil

Raoul Duke

unread,
Dec 11, 2012, 6:32:11 PM12/11/12
to clo...@googlegroups.com
one of the things which seem to be true but nowhere completely
successfully fleshed out is the fact that "equality" is very
subjective. there can and should be many different ways to pose and
answer the question "a == b".

Phil Hagelberg

unread,
Dec 11, 2012, 6:42:14 PM12/11/12
to clo...@googlegroups.com
There is a very good explanation of an objective equality predicate in
Henry Baker's "Equal Rights for Functional Objects" paper:
http://home.pipeline.com/~hbaker1/ObjectIdentity.html

Anyone interested in equality, FP, or why CL and Elisp are so annoying
to work with should read this paper. Keep in mind that Clojure cheats
in a few places in the name of convenience and doesn't quite implement
what he's described though.

-Phil

László Török

unread,
Dec 11, 2012, 6:44:23 PM12/11/12
to clo...@googlegroups.com

Hi,

Equality is never subjective. There maybe different equality relations defined. In most cases (integer) one os well served by intuition.
In other cases (clojure's =) the definition may not be intuitive, but never subjective.

László Török

unread,
Dec 11, 2012, 6:45:15 PM12/11/12
to clo...@googlegroups.com

Great paper btw!

Raoul Duke

unread,
Dec 11, 2012, 6:46:46 PM12/11/12
to clo...@googlegroups.com
> Equality is never subjective. There maybe different equality relations
> defined. In most cases (integer) one os well served by intuition.
> In other cases (clojure's =) the definition may not be intuitive, but never
> subjective.

ok sheesh then ^subjective^context dependent

Brian Marick

unread,
Dec 11, 2012, 7:22:26 PM12/11/12
to clo...@googlegroups.com

On Dec 11, 2012, at 5:42 PM, Phil Hagelberg <ph...@hagelb.org> wrote:

> Henry Baker's "Equal Rights for Functional Objects" paper:
> http://home.pipeline.com/~hbaker1/ObjectIdentity.html

Henry Baker was/is a brilliantly just-outside-of-the-box thinker. Many of the papers at http://home.pipeline.com/~hbaker1 are well worth reading. They're not as cohesive or as brilliant as the Lambda papers <http://library.readscheme.org/page1.html> but that's an awfully high bar.

--------
Occasional consulting on programming technique
Contract programming in Ruby and Clojure
Latest book: /Functional Programming for the Object-Oriented Programmer/
https://leanpub.com/fp-oo

Reply all
Reply to author
Forward
0 new messages