O Common Lisp tem muitos predicados de igualdade diferentes.
Isto é diferente de outras linguagens de programação, que podem ter apenas um ou dois (por exemplo, == e ===).
Alguns destes predicados no Common Lisp são específicos de tipos, enquanto outros são genéricos.
São estes últimos que vamos abordar aqui.
Há quatro predicados de igualdade genéricos e diferem no grau de restrição daquilo que consideram "igual".
São, por ordem do mais restritivo para o menos restritivo: eq, eql, equal e equalp.
Um conjunto rápido de definições (omitindo 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 o mesmo valor, dois carateres que são 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 como significando: 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; tudo 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 como significando: as strings e os carateres são comparados independentemente de serem maiúsculas ou minúsculas; os números são comparados com alguma conversão de tipo; as listas e os arrays são equalp se todos os elementos também forem equalp, as estruturas se forem do mesmo tipo e todos os slots forem equalp, e as hash-tables se as 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
A Leslie, a alienígena Lisp, está a programar o seu robô de labirinto (como é hábito entre os jovens alienígenas Lisp) e precisa de uma ajuda. O labirinto é composto por uma série de salas. Cada sala tem uma escolha de portas. Cada porta precisa de uma chave. Se usares a chave errada numa porta, é provável que ela expluda (não te preocupes com o robô, não vai haver danos, mas polir as marcas de queimaduras é bastante aborrecido para a Leslie). Se o robô não tiver uma chave que abra alguma das portas, a sala inteira explode! (Mais uma vez, não te preocupes, não vai causar danos, mas vai ser chato de limpar.)
O que precisas de fazer para ajudar a Leslie é dar ao robô a chave correta para cada sala. O robô usa a chave em cada porta da sala, por ordem, e passa pela primeira porta que se abrir.
Cada teste representa um labirinto e cada asserção é uma sala. Vais ter de escrever funções de predicado que devolvem T quando os argumentos são iguais e NIL quando não são.
Este labirinto tem apenas uma sala. Precisas de 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 iguais, não são o mesmo objeto.
Este labirinto tem duas salas. A primeira tem uma porta que se pode abrir se a tua chave conseguir dizer se dois números são estritamente iguais um ao outro. A segunda sala precisa de uma chave que permita alguma flexibilidade na verificação de números iguais.
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 se pode abrir se a tua chave conseguir dizer se dois carateres são estritamente iguais um ao outro. A segunda sala precisa de uma chave que permita uma comparação de carateres que não distinga 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 só predicados de igualdade muito permissivos não distinguem maiúsculas de minúsculas ao comparar dois carateres.
Tal como o labirinto dos carateres, a primeira sala precisa de uma chave que verifique se duas strings são iguais; a segunda sala precisa de uma chave que permita uma comparação que não distinga 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 só predicados de igualdade muito permissivos não distinguem maiúsculas de 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 verifica a igualdade de conses com conteúdos diferentes: símbolos, números, carateres, 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 olha para dentro de um cons, pode ainda não ser suficientemente permissivo para ignorar a distinção entre 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 só verificadores de igualdade muito permissivos verificam se o conteúdo do array é igual.
Inscreve-te no Exercism para aprenderes e dominares Common Lisp com 27 conceitos92 exercícios, e mentoria humana real, tudo grátis.