Common Lisp hat, wie andere Sprachen auch, eine Reihe von Regeln, mit denen sich entscheiden lässt, ob zwei Objekte „dieselben“ sind. Diese Regeln definieren vier Stufen, zu jeder gehört eine Funktion, die die Prüfung auf dieser Stufe durchführt. Die Stufen sind von der strengsten bis zur lockersten geordnet.
eqDie erste Stufe ist die Objektidentität.
Diese Gleichheit wird mit der Funktion eq geprüft.
Die beiden Objekte, die auf Gleichheit geprüft werden, müssen genau dasselbe Objekt sein:
(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)
eqlDie zweite Stufe ergänzt die Gleichheit von Zahlen und Zeichen.
Diese Gleichheit wird mit der Funktion eql geprüft.
Wie geprüft wird, hängt von den Typen der Argumente ab:
eq sind, sind auch eql
eql, wenn sie denselben Typ und denselben Wert habeneql, wenn sie dasselbe Zeichen darstellen.(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)
Man mag sich fragen, warum Zahlen und Zeichen nicht mit eq auf Objektidentität geprüft werden.
Der Common Lisp Standard erlaubt es Implementierungen, Zahlen und Zeichen zu kopieren, wenn sie das möchten.
Daher sind 0 und 0 möglicherweise nicht eq, weil es sich um verschiedene Instanzen der Zahl 0 handeln kann.
equalDie dritte Stufe prüft auf strukturelle Ähnlichkeit.
Diese Gleichheit wird mit equal geprüft.
Wie geprüft wird, hängt von den Typen der Argumente ab:
eq verwendeteeql verwendeteequal, wenn ihre Elemente equal sind.
Das geschieht rekursiv.equal, wenn ihre Elemente eql sindeq verwendeteequal, wenn sie funktional äquivalent sind.
(Hier gibt es Spielraum für implementierungsabhängiges Verhalten, was die Groß- und Kleinschreibung der Strings angeht, aus denen die Komponenten der Pfadnamen bestehen.)eq verwendete(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"
equalpDie vierte und lockerste Stufe der Gleichheit wird mit equalp geprüft.
Wie geprüft wird, hängt von den Typen ab:
equalp, dann sind sie equalp
equalp, wenn sie denselben Wert haben, auch wenn sie nicht denselben Typ habenequalp, wenn ihre Elemente equalp sind.
Das geschieht rekursiv.equalp, wenn sie dieselbe Anzahl Dimensionen haben, diese Dimensionen gleich sind und jedes Element equalp ist.equalp, wenn sie dieselbe Klasse und dieselben Slots haben und jeder dieser Slots zwischen den beiden Strukturen equalp ist.equalp, wenn sie beide dieselbe :test-Funktion haben, dieselben Schlüssel besitzen (verglichen mit dieser :test-Funktion) und diese Schlüssel dieselben Werte haben, verglichen mit 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`)
Die oben genannten sind die „generischen“ Gleichheitsfunktionen.
Sie funktionieren, wie definiert, für jeden Typ.
Das kann nützlich sein, wenn man generischen Code schreibt, der die Typen der Objekte, die er vergleichen wird, erst zur Laufzeit kennt.
Allerdings gilt es allgemein als „besserer Stil“, typspezifische Gleichheitsfunktionen zu verwenden, wenn man die Typen kennt, die verglichen werden.
Zum Beispiel string= statt equal.
Diese Funktionen werden in den jeweiligen Konzepten vorgestellt und besprochen.