O Common Lisp, tal como outras linguagens, tem um conjunto de regras para decidir se dois objetos são o 'mesmo'. Estas 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 estrito para o mais permissivo.
eqO primeiro nível é a identidade de objetos.
Esta igualdade é verificada com a função eq.
Os dois objetos cuja igualdade se verifica têm de 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 carateres.
Esta 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 tiverem o mesmo valoreql se representarem o mesmo caráter.(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)
Podes perguntar-te porque é que os números e os carateres não são comparados por identidade de objetos com eq.
A norma do Common Lisp permite que as implementações copiem números e carateres, se assim o entenderem.
Por isso, 0 e 0 podem não ser eq, uma vez que podem ser instâncias diferentes do número 0.
equalO terceiro nível verifica a semelhança estrutural.
Esta igualdade é verificada com equal.
A forma como a verificação é feita depende dos tipos dos argumentos:
eq
eql
equal se os seus elementos forem equal.
Isto é feito de forma recursiva.equal se os seus elementos forem eql
eq
equal se forem funcionalmente equivalentes.
(Há aqui margem para comportamento dependente da implementação no que diz respeito à distinção entre maiúsculas e minúsculas nas 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 são equalp
equalp se tiverem o mesmo valor, mesmo que não sejam do mesmo tipoequalp se os seus elementos forem equalp.
Isto é 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 comparados 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'.
Funcionam, tal como estão definidas, para qualquer tipo.
Isto pode ser útil quando escreves código genérico que não sabe quais os tipos dos objetos que vai comparar até ao momento da execução.
No entanto, considera-se geralmente "melhor estilo" usar funções de igualdade específicas por tipo quando conheces os tipos que estão a ser comparados.
Por exemplo, string= em vez de equal.
Estas funções serão apresentadas e discutidas nos conceitos relevantes.