Common Lisp tem muitos predicados de igualdade diferentes.
Isso é diferente de outras linguagens de programação, que podem ter apenas um ou dois (talvez == e ===, por exemplo).
Alguns desses predicados em Common Lisp são específicos de tipos, enquanto outros são genéricos.
São estes últimos que vamos abordar aqui.
Existem quatro predicados de igualdade genéricos, e eles diferem no quão restritivos são em relação ao que consideram "igual".
Eles são, em ordem do mais restritivo ao menos restritivo: eq, eql, equal e equalp.
Um conjunto rápido de definições (deixando de fora alguns detalhes) é o seguinte:
eq: define a igualdade como significando que os dois objetos são idênticos.
por exemplo:(eq 'a 'a) ; => T
(eq (list 1 2) (list 1 2)) ; => NIL
eql: define a igualdade como significando dois números com o mesmo tipo e valor, dois caracteres iguais, ou, para qualquer outra coisa, se forem eq.
por exemplo:(eql 1 1) ; => T
(eql #\a #\a) ; => T
(eql 1 1.0) ; => NIL
(eql #\a #\A) ; => NIL
equal: define a igualdade da seguinte forma: duas listas são equal se cada elemento também for equal; duas strings são equal se cada elemento for eql; dois arrays são equal se forem eq; todo o resto é equal se for eql.
por exemplo:(equal (list 1 2) (list 1 2)) ; => T
(equal #(1 2) #(1 2)) ; => NIL
(equal "foo" "foo") ; => T
equalp: define a igualdade da seguinte forma: strings e caracteres são comparados sem diferenciar maiúsculas de minúsculas; números são comparados com alguma conversão de tipo; listas e arrays são equalp se todo elemento também for equalp; estruturas, se forem do mesmo tipo e todos os slots forem equalp; e tabelas hash, se suas chaves e valores forem equalp
por exemplo:(equalp "foo" "FoO") ; => T
(equalp 3 3.0) ; => T
(equalp (make-a-structure :slot1 1 :slot2 2)
(make-a-structure :slot1 1 :slot2 2)) ; => T
Leslie, a Alienígena Lisp, está programando seu robô de labirinto (como jovens Alienígenas Lisp costumam fazer) e precisa de uma ajuda. O labirinto consiste em uma série de salas. Cada sala oferece opções de portas. Cada porta precisa de uma chave. Se você usar a chave errada em uma porta, ela provavelmente vai explodir (não se preocupe com o robô, não haverá danos, mas remover as marcas de queimado é bem chato para Leslie). Se o robô não tiver uma chave que abra alguma porta, a sala inteira vai explodir! (De novo, não se preocupe: não vai causar danos, mas vai ser chato de limpar.)
O que você precisa fazer para ajudar Leslie é dar ao robô a chave correta para cada sala. O robô vai usar a chave em cada porta da sala, na ordem, e passar pela primeira porta que abrir.
Cada teste representa um labirinto e cada asserção é uma sala. Você vai precisar escrever funções de predicado que resultam em T quando os argumentos são iguais e em NIL quando não são.
Este labirinto tem apenas uma única sala. Você precisa fornecer uma função que consiga dizer se dois objetos são o mesmo objeto.
Por exemplo:
a ; => "pizza"
b ; => "pizza"
(key-object-identity a a) ; => T
(key-object-identity a b) ; => NIL
porque, embora a e b pareçam ser o mesmo, não são o mesmo objeto.
Este labirinto tem duas salas. A primeira tem uma porta que pode ser aberta se a sua chave conseguir dizer se dois números são estritamente iguais entre si. A segunda sala precisa de uma chave que permita alguma flexibilidade ao verificar a igualdade de números.
Por exemplo:
a ; => 13
b ; => 13.0
c ; => 13
(key-numbers a b) ; => NIL
(key-numbers a c) ; => T
(key-numbers-of-different-types a b) ; => T
porque, embora a e b sejam numericamente iguais, são de tipos diferentes.
Este labirinto tem duas salas. A primeira tem uma porta que pode ser aberta se a sua chave conseguir dizer se dois caracteres são estritamente iguais entre si. A segunda sala precisa de uma chave que permita comparar os caracteres sem diferenciar maiúsculas de minúsculas.
Por exemplo:
a ; => #\X
b ; => #\x
c ; => #\X
(key-characters a b) ; => NIL
(key-characters a c) ; => T
(key-characters-case-insensitively a b) ; => T
porque apenas predicados de igualdade muito permissivos ignoram maiúsculas e minúsculas ao comparar dois caracteres.
Assim como o labirinto dos caracteres, a primeira sala precisa de uma chave que verifique se duas strings são iguais; a segunda sala precisa de uma chave que permita comparar sem diferenciar maiúsculas de minúsculas.
Por exemplo:
a ; => "pizza"
b ; => "PIZZA"
c ; => "pizza"
(key-strings a b) ; => NIL
(key-strings a c) ; => T
(key-strings-case-insensitively a b) ; => T
porque apenas predicados de igualdade muito permissivos ignoram maiúsculas e minúsculas ao comparar duas strings.
Este é um labirinto grande, com muitas salas. Cada sala precisa de uma chave que verifique se os conses contêm as coisas que são iguais. Cada sala vai verificar a igualdade de conses com conteúdos diferentes: símbolos, números, caracteres, e algumas vão precisar de definições de igualdade mais flexíveis para esses conteúdos.
Por exemplo:
syms-a ; => (left . right)
syms-b ; => (up . down)
syms-c ; => (left . right)
chars-a ; => (#\x . #\y)
chars-b ; => (#\x . #\Y)
chars-c ; => (#\x . #\y)
nums-a ; => (13 . 23)
nums-b ; => (13 . 23.0)
nums-c ; => (13 . 23)
(key-conses-of-symbols syms-a syms-b) ; => NIL
(key-conses-of-symbols syms-a syms-c) ; => T
(key-conses-of-characters chars-a chars-b) ; => NIL
(key-conses-of-characters chars-a chars-c) ; => T
(key-conses-of-characters-case-insensitively
chars-a chars-b) ; => T
(key-conses-of-numbers nums-a nums-b) ; => NIL
(key-conses-of-numbers nums-a nums-c) ; => T
(key-conses-of-numbers-of-different-types
nums-a nums-b) ; => T
porque, mesmo com um predicado de igualdade que olhe para dentro de um cons, ele ainda pode não ser permissivo o bastante para ignorar maiúsculas e minúsculas ou o tipo numérico ao comparar.
Este labirinto é mais simples, com apenas duas salas. A primeira precisa de uma chave que verifique se os arrays são os mesmos arrays. A segunda precisa de uma chave que verifique o conteúdo dos arrays.
Por exemplo:
a ; => #[13 23]
b ; => #[13 23]
c ; => #[13 23.0]
(key-arrays a b) ; => NIL
(key-arrays a c) ; => NIL
(key-arrays-loosely a b) ; => T
(key-arrays-loosely a c) ; => T
porque apenas verificadores de igualdade muito permissivos vão verificar se o conteúdo do array é igual.
Crie sua conta no Exercism para aprender e dominar Common Lisp com 27 conceitos92 exercícios e mentoria humana de verdade, tudo de graça.