Trilhas
/
Common Lisp
Common Lisp
/
Exercícios
/
A chave da comparação
A chave da comparação

A chave da comparação

Exercício de aprendizagem

Introdução

Igualdade

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

Instruções

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.

1. O labirinto da igualdade de objetos

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.

2. O labirinto dos números

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.

3. O labirinto dos caracteres

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.

4. O labirinto das strings

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.

5. O labirinto dos conses

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.

6. O labirinto dos arrays

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.

Editar via GitHub O link abre em uma nova janela ou aba
Common Lisp Exercism

Tudo pronto para começar A chave da comparação?

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.