enums - the - typedef enum c
Common Lisp equivalente a C enums (3)
Intento aprender algo de Lisp (Common Lisp) últimamente, y me pregunto si hay alguna forma de dar un nombre a los números constantes, tal como lo puedes hacer en C a través de enumeraciones.
No necesito el conjunto completo de funciones de enumeraciones. Al final solo quiero tener un código rápido y legible.
Probé funciones globales y pequeñas, pero eso siempre tuvo una degradación en el rendimiento. Solo conectar los números al código siempre fue más rápido.
La forma normal de hacer enumeraciones en Lisp es usar símbolos. Los símbolos son internados (reemplazados por punteros a sus entradas en una tabla de símbolos) por lo que son tan rápidos como enteros y legibles como las constantes enumeradas en otros idiomas.
Entonces, en C podrías escribir:
enum { apple, orange, banana, };
En Lisp puedes usar ''apple
''orange
, ''orange
''banana
y ''banana
directamente.
Si necesita un tipo enumerado, puede definir uno con deftype
:
(deftype fruit () ''(member apple orange banana))
y luego puedes usar el tipo de fruit
en declare
, typep
, typecase
, etc. y puedes escribir funciones genéricas que se especializan en ese tipo .
Los mensajes son redundantes para Lisp, porque todos los símbolos son su propia identidad, por lo que puedes usarlos, por ejemplo:
[dsm@localhost:~]$ clisp -q
[1]> (setf x ''some) ;''
SOME
[2]> (eq x ''some) ;''
T
[3]>
Por ejemplo, desea nombrar los tamaños de fuente:
(defconstant +large+ 3)
(defconstant +medium+ 2)
(defconstant +small+ 1)
Podría escribir una macro para acortarla.
Por encima de las definiciones constantes, generalmente se escriben SÓLO cuando estos números se deben pasar a algún código externo no Lisp.
De lo contrario, uno solo usaría los símbolos de palabra clave:: grande,: mediano y: pequeño.
Puedes probarlos con EQ y todo lo que use alguna prueba de igualdad.
(let ((size :medium))
(ecase size
(:small ...)
(:medium ...)
(:large ...)))
También puedes escribir métodos para ello:
(defmethod draw-string (message x y (size (eql :large))) ...)
Como se mencionó, puedes definir un tipo de conjunto:
(deftype size () ''(member :small :medium :large))
Entonces puedes verificar si algo es cualquiera de esos:
(let ((my-size :medium))
(check-type my-size size))
Arriba indicaría un error si my-size no es uno de: small,: medium o: large.
También puede usar el tipo en una forma defclass:
(defclass vehicle ()
((width :type size :initarg :width)))
Ahora crearía objetos como aquí:
(make-instance ''vehicle :width :large)
Algunas implementaciones de Common Lisp verifican cuando configura la ranura a algún valor ilegal.
Si ahora crea objetos del vehículo de clase, las ranuras serán una de: grande, mediana o pequeña. Si miras el objeto en un depurador, inspector u otra herramienta, verás los nombres simbólicos y no 1, 2 o 3 (o los valores que normalmente usarías).
Esto es parte del estilo Lisp: use nombres simbólicos cuando sea posible. Use símbolos con valores numéricos solo en el código de interfaz para funciones extranjeras (como llamar al código C externo que usa enumeraciones).