11 ms·
> Overall, I find complaints about the equality predicates to be based on a misunderstanding of the definition of "equality". It's more that LISP is the only l
by shadowgovt 2y ago
> Overall, I find complaints about the equality predicates to be based on a misunderstanding of the definition of "equality".
It's more that LISP is the only language I know that exposes how complex the concept of equality actually is. All the other ones I use more-or-less make an implicit assumption that equality means one of the things that LISP offers but if you want the other definitions of equality you either have to build support for them by hand or call out to a library function that's going to use (static or dynamic) reflection to reduce the problem to the one kind of equality the language implements.
(Apart from that, the only other complaint is that LISP being as old as it is, the default names for those equalities are too terse to self-describe. You just have to memorize which one is 'eq' and which one is 'eql', there's no way to guess looking at the names themselves).
- kazinator 2y agoCommon Lisp doesn't do a very good job, unfortunately. [1]> (equal '(1 2 3) '(1 2 3)) T [2]> (equal "abc" "abc") T [3]> (equal #(1 2 3) #(1 2 3)) NIL [4]> (subtypep 'string 'vector) T ; T So a string is formally a kind of vector according to t he type system itself, but vectors don't use equal comparison whereas strings do. We can reach for equalp: [1]> (equalp #(1 2 3) #(1 2 3)) T But then we have to accept, something we might not necessarily want: [2]> (equalp #(1 2 3) #(1 2 3.0)) T which will not be true under the equal function that we really wanted to Just Work for simple vectors: [3]> (equal '(1 2 3) '(1 2 3.0)) NIL eql being the default equality function throughout the library is also suboptimal. The specification allows (eq 1 1) to be false, which caters to unrealistically poor implementations such as ones that heap-allocate all integers. This, in spite of the fact that fixnum is required to be at least 16 bits wide: most-positive-fixnum must be at least 32767, and the fixnum type must be a supertype of (signed-byte 16). What this means is that if Common Lisp were fit into a 16 bit machine (good luck with that at all), it would have to provide 16 bit fixnums (easily doable, but not unboxed ones) which defeats the fixnum concept of fixnums being the unboxed range of integers, beyond which we have boxed bignums.
- koito17 2y agovectors don't use equal comparison whereas strings do This behavior is required by the specification. From https://www.lispworks.com/documentation/HyperSpec/Body/f_equal.htm https://www.lispworks.com/documentation/HyperSpec/Body/f_equ... , Two arrays are equal only if they are eq, with one exception: strings and bit vectors are compared element-by-element (using eql). What makes strings and bit vectors special, in my opinion, is that they are homogeneous arrays. Heterogeneous arrays aren't something that I often use outside of Clojure (usually because they are awkward to use in statically typed languages). The specification allows (eq 1 1) to be false Because the specification doesn't limit the magnitude of numbers nor state how they should be stored in memory. The scenario you've described requires an implementation that intentionally makes every number a bignum or an instance of a class (like Smalltalk).
- kazinator 2y agoLists can be heterogeneous and often are, yet equal recurses on them. If you have list-based code that uses equal, you have extra work to do if you want to convert it to vectors. Vectors comparable with equal make good hash table keys when heterogeneous keys are needed which don't need the structural flexibility of lists.