Rutas
/
Common Lisp
Common Lisp
/
Ejercicios
/
La clave de la comparación
La clave de la comparación

La clave de la comparación

Ejercicio de aprendizaje

Introducción

Igualdad

Common Lisp tiene muchos predicados de igualdad distintos. Esto difiere de otros lenguajes de programación que pueden tener solo uno o dos (por ejemplo, quizá == y ===). Algunos de estos predicados en Common Lisp son específicos de tipos, mientras que otros son genéricos. Estos últimos son los que se tratarán aquí.

Hay cuatro predicados de igualdad genéricos y se diferencian en cuán restrictivos son con lo que consideran «igual». Son, en orden de más restrictivo a menos restrictivo: eq, eql, equal y equalp.

Estas son unas definiciones rápidas (omitimos algunos detalles):

  • eq: define la igualdad como que los dos objetos son idénticos. p. ej.:
(eq 'a 'a)                 ; => T
(eq (list 1 2) (list 1 2)) ; => NIL
  • eql: define la igualdad como: dos números con el mismo tipo y valor, dos caracteres que son iguales o, para cualquier otra cosa, si son eq. p. ej.:
(eql 1 1)     ; => T
(eql #\a #\a) ; => T
(eql 1 1.0)   ; => NIL
(eql #\a #\A) ; => NIL
  • equal: define la igualdad como: dos listas son equal si cada elemento también es equal; dos strings son equal si cada elemento es eql; dos arrays son equal si son eq; todo lo demás es equal si es eql. p. ej.:
(equal (list 1 2) (list 1 2)) ; => T
(equal #(1 2) #(1 2))         ; => NIL
(equal "foo" "foo")           ; => T
  • equalp: define la igualdad como: los strings y los caracteres se comparan sin distinguir entre mayúsculas y minúsculas; los números se comparan con cierta conversión de tipos; las listas y los arrays son equalp si cada elemento también es equalp; las estructuras, si son del mismo tipo y todas sus ranuras son equalp; y las tablas hash, si sus claves y valores son equalp. p. ej.:
(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

Instrucciones

Leslie, el alienígena de Lisp, está programando su robot de laberintos (como suelen hacer los jóvenes alienígenas de Lisp) y necesita ayuda. El laberinto consta de una serie de salas. Cada sala ofrece una serie de puertas entre las que elegir. Cada puerta necesita una llave. Si usas la llave equivocada en una puerta, es probable que explote (no te preocupes por el robot, no sufrirá ningún daño, pero pulir las marcas de quemaduras es bastante molesto para Leslie). Si el robot no tiene ninguna llave que abra alguna puerta, ¡la sala entera explotará! (De nuevo, no te preocupes: no causará daños, pero limpiarlo será un fastidio).

Lo que tienes que hacer para ayudar a Leslie es darle al robot la llave correcta para cada sala. El robot usará la llave en cada puerta de la sala en orden y atravesará la primera puerta que se abra.

Cada test representa un laberinto y cada afirmación es una sala. Tendrás que escribir funciones de predicado que devuelvan T cuando los argumentos sean iguales y NIL cuando no lo sean.

1. El laberinto de la igualdad de objetos

Este laberinto tiene una sola sala. Tienes que proporcionar una función que sepa decir si dos objetos son el mismo objeto.

Por ejemplo:

a                         ; => "pizza"
b                         ; => "pizza"

(key-object-identity a a) ; => T
(key-object-identity a b) ; => NIL

porque, aunque a y b parezcan ser lo mismo, no son el mismo objeto.

2. El laberinto de los números

Este laberinto tiene dos salas. La primera tiene una puerta que se puede abrir si tu llave sabe distinguir si dos números son estrictamente iguales entre sí. La segunda sala necesita una llave que permita cierta flexibilidad al comprobar si dos números son iguales.

Por ejemplo:

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, aunque a y b sean numéricamente iguales, son de tipos diferentes.

3. El laberinto de los caracteres

Este laberinto tiene dos salas. La primera tiene una puerta que se puede abrir si tu llave sabe distinguir si dos caracteres son estrictamente iguales entre sí. La segunda sala necesita una llave que permita comparar los caracteres sin distinguir entre mayúsculas y minúsculas.

Por ejemplo:

a                                       ; => #\X
b                                       ; => #\x
c                                       ; => #\X

(key-characters a b)                    ; => NIL
(key-characters a c)                    ; => T
(key-characters-case-insensitively a b) ; => T

porque solo los predicados de igualdad muy permisivos ignoran las mayúsculas y las minúsculas al comparar dos caracteres.

4. El laberinto de los strings

Al igual que en el laberinto de los caracteres, la primera sala necesita una llave que compruebe si dos strings son iguales; la segunda sala necesita una llave que permita compararlos sin distinguir entre mayúsculas y minúsculas.

Por ejemplo:

a                                    ; => "pizza"
b                                    ; => "PIZZA"
c                                    ; => "pizza"

(key-strings a b)                    ; => NIL
(key-strings a c)                    ; => T
(key-strings-case-insensitively a b) ; => T

porque solo los predicados de igualdad muy permisivos ignoran las mayúsculas y las minúsculas al comparar dos strings.

5. El laberinto de los conses

Este es un laberinto grande, con muchas salas. Cada sala necesita una llave que compruebe si los conses contienen cosas que son iguales. Cada sala comprobará la igualdad de conses con contenidos diferentes: símbolos, números, caracteres, y algunas necesitarán definiciones de igualdad más flexibles para esos contenidos.

Por ejemplo:

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, incluso con un predicado de igualdad que mira dentro de un cons, puede que no sea lo bastante permisivo como para ignorar las mayúsculas y las minúsculas o el tipo numérico al comparar.

6. El laberinto de los arrays

Este laberinto es más sencillo, con solo dos salas. La primera necesita una llave que compruebe si los arrays son los mismos arrays. La segunda necesita una llave que compruebe el contenido de los arrays.

Por ejemplo:

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 solo los comparadores de igualdad muy permisivos comprueban si el contenido del array es igual.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Common Lisp Exercism

¿Listo para empezar La clave de la comparación?

Regístrate en Exercism para aprender y dominar Common Lisp con 27 conceptos92 ejercicios y mentoría humana real, todo gratis.