Common Lisp, como outras linguagens, tem um conjunto de regras para decidir se dois objetos são o "mesmo". Essas regras definem quatro níveis, cada um com uma função que faz esse nível de verificação. Os níveis estão ordenados do mais rigoroso ao mais permissivo.
eqO primeiro nível é a identidade do objeto.
Essa igualdade é verificada com a função eq.
Os dois objetos comparados precisam ser exatamente o mesmo objeto:
(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)
eqlO segundo nível acrescenta a igualdade de números e caracteres.
Essa igualdade é verificada com a função eql.
A forma como a verificação é feita depende dos tipos dos argumentos:
eq são eql
eql se forem do mesmo tipo e valoreql se representarem o mesmo caractere.(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)
A gente pode se perguntar por que números e caracteres não são comparados por identidade de objeto com eq.
O padrão do Common Lisp permite que as implementações copiem números e caracteres, se quiserem.
Por isso, 0 e 0 podem não ser eq, já que podem ser instâncias diferentes do número 0.
equalO terceiro nível verifica a semelhança estrutural.
Essa igualdade é verificada com equal.
A forma como a verificação é feita depende dos tipos dos argumentos:
eq
eql
equal se seus elementos forem equal.
Isso é feito de forma recursiva.equal se seus elementos forem eql
eq
equal se forem funcionalmente equivalentes.
(Há espaço aqui para comportamento dependente da implementação no que diz respeito à diferenciação entre maiúsculas e minúsculas das strings que compõem os componentes dos 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"
equalpO quarto e mais permissivo nível de igualdade é verificado com equalp.
A forma como a verificação é feita depende dos tipos:
equalp, então eles são equalp
equalp se tiverem o mesmo valor, mesmo que não sejam do mesmo tipoequalp se seus elementos forem equalp.
Isso é feito de forma recursiva.equalp se tiverem o mesmo número de dimensões, se essas dimensões forem iguais e se cada elemento for equalp.equalp se tiverem a mesma classe e os mesmos slots e se cada um desses slots for equalp entre as duas estruturas.equalp se ambas tiverem a mesma função :test, se tiverem as mesmas chaves (comparadas com essa função :test) e se essas chaves tiverem os mesmos valores quando comparadas com 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`)
As funções acima são as funções de igualdade "genéricas".
Elas funcionam, conforme definidas, para qualquer tipo.
Isso pode ser útil quando se escreve código genérico que só vai saber os tipos dos objetos que vai comparar em tempo de execução.
No entanto, geralmente se considera "melhor estilo" usar funções de igualdade específicas de tipo quando se conhecem os tipos comparados.
Por exemplo, string= em vez de equal.
Essas funções serão apresentadas e discutidas nos conceitos relevantes.