Common Lisp, comme d'autres langages, possède un ensemble de règles pour décider si deux objets sont « les mêmes ». Ces règles définissent quatre niveaux, chacun avec une fonction qui effectue ce niveau de vérification. Ces niveaux sont ordonnés du plus strict au plus permissif.
eqLe premier niveau est l'identité des objets.
Cette égalité se vérifie avec la fonction eq.
Les deux objets dont on vérifie l'égalité doivent être exactement le même objet :
(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)
eqlLe deuxième niveau ajoute l'égalité des nombres et des caractères.
Cette égalité se vérifie avec la fonction eql.
La façon dont la vérification est effectuée dépend des types des arguments :
eq sont eql
eql s'ils sont du même type et de la même valeureql s'ils représentent le même caractère.(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)
On peut se demander pourquoi les nombres et les caractères ne sont pas comparés par identité d'objet avec eq.
La norme Common Lisp autorise les implémentations à copier les nombres et les caractères si elles choisissent de le faire.
Ainsi, 0 et 0 peuvent ne pas être eq, car il peut s'agir d'instances différentes du nombre 0.
equalLe troisième niveau vérifie la similarité structurelle.
Cette égalité se vérifie avec equal.
La façon dont la vérification est effectuée dépend des types des arguments :
eq
eql
equal si leurs éléments sont equal.
La comparaison est effectuée récursivement.equal si leurs éléments sont eql
eq
equal s'ils sont équivalents du point de vue fonctionnel.
(Le comportement dépendant de l'implémentation est possible ici en ce qui concerne la sensibilité à la casse des chaînes qui constituent les composants des 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"
equalpLe quatrième niveau d'égalité, le plus permissif, se vérifie avec equalp.
La façon dont la vérification est effectuée dépend des types :
equalp, alors ils sont equalp
equalp s'ils ont la même valeur, même s'ils ne sont pas du même typeequalp si leurs éléments sont equalp.
La comparaison est effectuée récursivement.equalp s'ils ont le même nombre de dimensions, que ces dimensions sont identiques et que chaque élément est equalp.equalp si elles ont la même classe et les mêmes slots, et si chacun de ces slots est equalp entre les deux structures.equalp si elles ont toutes les deux la même fonction :test, qu'elles ont les mêmes clés (comparées avec cette fonction :test) et que ces clés ont les mêmes valeurs quand on les compare avec 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`)
Les fonctions ci-dessus sont les fonctions d'égalité « génériques ».
Telles qu'elles sont définies, elles fonctionnent pour n'importe quel type.
Cela peut être utile lorsqu'on écrit du code générique qui ne connaît les types des objets qu'il va comparer qu'à l'exécution.
Cependant, il est généralement considéré comme préférable d'utiliser des fonctions d'égalité spécifiques à un type lorsqu'on connaît les types comparés.
Par exemple string= plutôt que equal.
Ces fonctions seront présentées et abordées dans les concepts correspondants.