Common Lisp hat eine ganze Reihe unterschiedlicher Vergleichsoperatoren. Auf den ersten Blick ist das verwirrend, aber wichtig zu wissen. Die Operatoren unterscheiden sich darin, was sie als „gleich“ erkennen. Dazu gibt es die universellen Funktionen
eqeqlequalequalp
In der gezeigten Reihenfolge lockert Lisp die Regeln, wann zwei „Objekte“ als gleich betrachtet werden. Die Abstufungen reichen dabei von „die Objekte sind identisch“ bis hin zu „die Objekte sind eher ähnlicch statt gleich„
eq – Identität statt Gleichheit
Die am meisten strikte Prüfung nimmt eq vor. Es liefert nur dann t, wenn die zu prüfenden Objekte identisch sind – sie verweisen auf ein und dasselbe Objekt im Speicher.
(eq 'a 'a) ; --> T
(eq 1 1) ; --> T
(eq 1 1.0) ; --> NIL
(eq "A" "A") ; --> NIL
(eq (list 1 2) (list 1 2)) ; --> NIL
Merke: eq prüft Identität, NICHT Gleichheit
Wichtig ist, das die beiden Strings „A“ aus dem Beispiel NICHT gleich bezüglich ‚eq‘ sind, dieses Wissen wird uns später noch nützen.
eql – leichte Lockerung der Regeln
Zwei Lisp-Objekte a und b sind eql (liefern also T im Vergleich), wenn eine der folgenden Bedingungen erfüllt sind:
aundbsind „eq“. Beide Objekte sind identisch (s. o.)aundbsind Zahlenwerte gleichen Typs und gleichen Wertes. Ein Integer1und ein Float1.0sind dementsprechend NICHTeql-
aundbsind vom Typ Character und repräsentieren den gleichen Characterwert
Wichtig zu wissen ist, dass eql bei vielen Funktionen in Common Lisp der Defaultvergleichsoperator ist. Beispiele dazu sind:
- Vergleiche von Schlüsselwerten bei Hashtabellen. Dies kann beim Anlegen einer neuen Hashtabelle (
make-hash-table) mit dem Parameter:testgeändert werden. - …
Gerade der Einsatz in einer Hashtable liefert dadurch überraschende Ergebnisse, wenn die Schlüsselwerte Strings sind:
(defvar *h* (make-hash-table))
(setf (gethash "one" *h*) 1)
(gethash "one" *h*) ;; --> NIL. Warum????
;; Darum
(eql "one" "one") ;; --> NIL
Wenn die Schlüssel Strings seien sollen, dann darf die Hashtable nicht mit eql als Testfunktion angelegt werden. Hier bietet sich dann an, equal zu benutzen:
(setq *h* (make-hash-table :test 'equal))
equal – Inhaltliche Gleichheit
TBD.
equalp – Mehr „ähnlich“ als „gleich“
TBD.
Die Spezialisierten
= für Zahlen
string= und string-equal für Zeichenketten
Wie der Name schon vermuten lässt, vergleicht string= zwei Strings auf Gleichheit. Optional lässt sich dabei mit :start1, :end1 und :start2, :end2 jeweils ein zu vergleichender Teilbereich der beiden Strings angeben. Um als „Gleich“ zu gelten, müssen zwei Strings (oder die ausgewählten Substrings)
- die gleiche Länge haben
- An allen Positionen die Zeichen gleich sein (
char=)
string-equal weicht das zweite Kriterium dahin gehend auf, dass die Zeichen ohne Berücksichtigung von Groß- und Kleinschreibung verglichen werden (die Zeichen sind char-equal statt char=)
char= und char-equal für Zeichen
char= liefert T, wenn alle übergebenen Zeichen gleich sind. char-equal macht das gleiche, ignoriert dabei jedoch Groß- und Kleinschreibung.