You actually can compare everything with eq
, eql
, equal
and equalp
. But choose for yourself, what's needed:
It's easy to think that eq
compare pointers. Thus symbols (because a unique symbol enters package only once and its address is the same in every case you use it) will return true.
CL-USER> (eq 'a 'a)
T
Next, different lists, even if contain the same values, are not equal (in terms of eq
). They have different addresses, they are different objects.
CL-USER> (defparameter *a* '(1 2))
*A*
CL-USER> (defparameter *b* '(1 2))
*B*
CL-USER> (eq *a* *b*)
NIL
But it's not always true, for example if you're dealing with literal object:
CL-USER> (lambda nil '(1 2 3))
#<FUNCTION :LAMBDA NIL '(1 2 3)>
CL-USER> (eq * *)
T
While:
CL-USER> (eq '(1 2 3) '(1 2 3))
NIL
Tricky? You may expect that values of different variables that contain the same numbers will not be equal, since the numbers should occupy different blocks of memory, but...
CL-USER> (defparameter *c* 5)
*C*
CL-USER> (defparameter *d* 5)
*D*
CL-USER> (eq *c* *d*)
T
Description of eq
function says about identical objects, so number five is the same object everywhere.
Next, eql
function is defined upon eq
, it evaluates t
in the following cases:
- If x and y are
eq
.
- If x and y are both numbers of the same type and the same value.
- If they are both characters that represent the same character.
And equal
, equalp
deal with 'visually similar' objects.
Why so many of them? Think for yourself: in language like LISP where you do not work with pointers explicitly you may want to find exactly the same object (at the same address) in list or anywhere.. So you need function that acts on this 'pointer' level. Next it's obvious that you need 'normal' comparison functions and here they are. Differences are subtle and somewhat historic, but it's often useful to have them all.
It's also important to note that some of these 4 base comparison functions have additional meaning being applied to certain types of data. For example equal
works for comparison of strings in case-sensitive manner, while equalp
in case-insensitive one.
CL-USER> (equal "My String" "My String")
T
CL-USER> (equal "My String" "My string")
NIL
CL-USER> (equalp "My String" "My string")
T
To continue with the string example, here are many functions like string=
, etc. Why? That's what 'The Common Lisp Cookbook' says:
You'll want to use these if you're deploying implementation-defined attributes of characters. Check your vendor's documentation in this case.
However, in vast majority of cases the 4 basic functions will be enough.