Common Lisp, like other languages has a set of rules on how to decide if two objects are the 'same'. These rules define four levels, each with a function that performs that level of checking. The levels are ordered from strictest to loosest.
eqThe first level is object identity.
This equality is checked with the function eq.
The two objects being checked for equality must be the very same object:
(eq 'apples 'apples) ; => T
(eq 'apples 'oranges) ; => NIL
(eq '(a b c) '(a b c) ; => NIL (these two lists have the same contents but are not the same list)
(let ((list1 '(a b c)) (list2 list1))
(eq list1 list2)) ; => T (these two lists are the same list)
eqlThe second level adds equality of numbers and characters.
This equality is checked with the function eql.
The way the checking is done depends upon the types of the arguments:
eq are eql
eql if they are of the same type and valueeql if they they represent the same character.(eql 1 1) ; => T
(eql 1 1/1) ; => NIL (one number is an integer, the other a rational)
(eql #\c #\c) ; => T
(eql #\c #\C) ; => NIL (case is different)
One may wonder why numbers and characters are not compared for object identity with eq.
The Common Lisp standard allows implementations to copy numbers and characters if they choose to do so.
Thus 0 and 0 may not be eq as they may be different instances of the number 0.
equalThe third level checks for structural similarity.
This equality is checked with equal.
The way the checking is done depends upon the types of the arguments:
eq
eql
equal if their elements are equal.
This is done recursively.equal if their elements are eql
eq
equal if they are functionality equivalent.
(There is room for implementation dependent behavior here with regards to case sensitivity of the strings which make up the components of the pathnames.)eq
(equal '(a (b c)) '(a (b c))) ; => T (conses are equal if their contents are equal)
(equal "hello" "hello") ; => T
(equal "hello" "HELLO") ; => NIL
(equal #(1 2 3) #(1 2 3)) ; => NIL (arrays are equal only if eq)
(equal #P"foo/bar.md" #P"foo/bar.md") ; => T (pathnames are equal if "functionally equivalent"
equalpThe fourth and most loose level of equality is checked with equalp.
The how the checking is done depends upon the types:
equalp then they are equalp
equalp if they have the same value even if they are not of the same typeequalp if their elements are equalp.
This is done recursively.equalp if they have the same number of dimensions, those dimensions are the same, and each element is equalp.equalp if they have the same class and slots and each of those slots are equalp between the two structures.equalp if they both have the same :test function, they have the same keys (as compared with that :test function) and that those keys have the same values as compared with equalp.(equalp 1 1.0) ; => T
(equalp #\c #\C) ; => T
(equalp "hello" "HELLO") ; => T
(equalp #(1 2 3) #(1.0 2.0 3.0)) ; => T (arrays contain elements which are `equalp`)
(equal #S(TEST :SLOT1 'a :SLOT2 'b)
#S(TEST :SLOT1 'a :SLOT2 'b)) ; => T (structures of the same class with slots that have values which are `equalp`)
The above are the 'generic' equality functions.
They work, as defined, for any type.
This can be useful when one writes generic code that does not know the types of objects it will be comparing until run-time.
However it is generally considered "better style" to use type specific equality functions when one knows the types being compared.
For example string= rather than equal.
These functions will be presented and discussed in the relevant concepts.