A Common Lisp a többi nyelvhez hasonlóan szabályokkal rendelkezik arra vonatkozóan, hogyan döntse el, hogy két objektum ugyanaz-e. Ezek a szabályok négy szintet határoznak meg, és mindegyik szinthez tartozik egy függvény, amely elvégzi az adott szintű ellenőrzést. A szintek a legszigorúbbtól a legmegengedőbbig követik egymást.
eqAz első szint az objektumazonosság.
Ezt az egyenlőséget az eq függvénnyel ellenőrizzük.
A két objektumnak, amelyet egyenlőség szempontjából vizsgálunk, pontosan ugyanaz az objektum kell lennie:
(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)
eqlA második szint kiegészül a számok és a karakterek egyenlőségével.
Ezt az egyenlőséget az eql függvénnyel ellenőrizzük.
Az ellenőrzés módja az argumentumok típusától függ:
eq, akkor azok eql iseql, ha azonos típusúak és azonos értékűekeql, ha ugyanazt a karaktert reprezentálják.(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)
Felmerülhet a kérdés, miért nem hasonlítjuk össze a számokat és a karaktereket objektumazonosság szempontjából az eq függvénnyel.
A Common Lisp szabvány megengedi az implementációknak, hogy lemásolják a számokat és a karaktereket, ha úgy döntenek.
Így előfordulhat, hogy 0 és 0 nem eq, mert a 0 szám különböző példányai lehetnek.
equalA harmadik szint a szerkezeti hasonlóságot vizsgálja.
Ezt az egyenlőséget az equal függvénnyel ellenőrizzük.
Az ellenőrzés módja az argumentumok típusától függ:
eq függvényt használnánkeql-t használnánkequal, ha az elemeik is equal.
Ez rekurzívan történik.equal, ha az elemeik eql
eq lenneequal, ha funkcionálisan egyenértékűek.
(Itt helye van az implementációfüggő viselkedésnek, ami az elérési útnevek komponenseit alkotó stringek kis- és nagybetű-érzékenységét illeti.)eq lenne(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"
equalpA negyedik, legmegengedőbb egyenlőségi szintet az equalp függvénnyel ellenőrizzük.
Az ellenőrzés módja a típusoktól függ:
equalp, akkor azok equalp
equalp, ha azonos az értékük, még akkor is, ha nem azonos a típusukequalp, ha az elemeik is equalp.
Ez rekurzívan történik.equalp, ha ugyanannyi dimenziójuk van, ezek a dimenziók megegyeznek, és minden elemük equalp.equalp, ha ugyanabba az osztályba tartoznak, ugyanazok a slotjaik, és ezek a slotok equalp a két struktúra között.equalp, ha ugyanaz a :test függvényük, ugyanazok a kulcsaik (az adott :test függvénnyel összehasonlítva), és ezekhez a kulcsokhoz ugyanazok az értékek tartoznak equalp szerint összehasonlítva.(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`)
A fentiek az „általános” egyenlőségfüggvények.
A definíciójuk szerint bármely típusra működnek.
Ez akkor lehet hasznos, ha olyan általános kódot írunk, amely futásidőig nem tudja, milyen típusú objektumokat fog összehasonlítani.
Azonban általában „szebb stílusnak” számít típusspecifikus egyenlőségfüggvényeket használni, ha ismerjük az összehasonlítandó típusokat.
Például a string=-t az equal helyett.
Ezeket a függvényeket a vonatkozó fogalmaknál mutatjuk be és tárgyaljuk.