Tracks
/
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 diferentes. Esto es distinto de otros lenguajes de programación que pueden tener solo uno o dos (quizás == y ===, por ejemplo). Algunos de estos predicados en Common Lisp son específicos de ciertos tipos, mientras que otros son genéricos. Aquí veremos estos últimos.

Hay cuatro predicados de igualdad genéricos y se diferencian en qué tan estrictos son con lo que consideran «igual». Son, en orden del más restrictivo al menos restrictivo: eq, eql, equal y equalp.

Un conjunto rápido de definiciones (dejando fuera algunos detalles) es el siguiente:

  • eq: define la igualdad como que los dos objetos son idénticos. por ejemplo:
(eq 'a 'a)                 ; => T
(eq (list 1 2) (list 1 2)) ; => NIL
  • eql: define la igualdad como que dos números tienen el mismo tipo y el mismo valor, que dos caracteres son iguales, o, para cualquier otra cosa, que son eq. por ejemplo:
(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. por ejemplo:
(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 mayúsculas de minúsculas; los números se comparan con cierta conversión de tipo; las listas y los arrays son equalp si cada elemento también es equalp, las estructuras si son del mismo tipo y todos sus slots son equalp, y las tablas hash si sus claves y sus valores son equalp. por ejemplo:
(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 laberinto (como suelen hacer los jóvenes alienígenas de Lisp) y necesita algo de ayuda. El laberinto consiste en una serie de habitaciones. Cada habitación tiene varias 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 habrá daños, pero pulir las marcas de quemadura es bastante molesto para Leslie). Si el robot no tiene una llave que abra alguna de las puertas, ¡toda la habitación explotará! (De nuevo, no te preocupes, no causará daños, pero será molesto de limpiar).

Lo que necesitas para ayudar a Leslie es darle al robot la llave correcta para cada habitación. El robot usará la llave en cada puerta de la habitación en orden y pasará por la primera puerta que se abra.

Cada prueba representa un laberinto y cada aserción es una habitación. Tendrás que escribir funciones predicado que evalúen a 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 habitación. Necesitas proporcionar una función que pueda 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 habitaciones. La primera tiene una puerta que se puede abrir si tu llave puede decir si dos números son estrictamente iguales entre sí. La segunda habitación necesita una llave que permita cierta flexibilidad al comprobar si los 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 habitaciones. La primera tiene una puerta que se puede abrir si tu llave puede decir si dos caracteres son estrictamente iguales entre sí. La segunda habitación 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 minúsculas al comparar dos caracteres.

4. El laberinto de los string

Al igual que el laberinto de los caracteres, la primera habitación necesita una llave que compruebe si dos string son iguales; la segunda habitación necesita una llave que permita comparar 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 minúsculas al comparar dos string.

5. El laberinto de los cons

Este es un laberinto grande con muchas habitaciones. Cada habitación necesita una llave que compruebe si los cons contienen las cosas que son iguales. Cada habitación comprobará la igualdad de cons 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 mire dentro de un cons, puede que no sea lo bastante permisivo para ignorar las mayúsculas y minúsculas o el tipo numérico al comparar.

6. El laberinto de los arrays

Este laberinto es más sencillo, con solo dos habitaciones. 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 comprobadores de igualdad muy permisivos verificarán que el contenido del array sea igual.

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

¿Todo 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.