2009-02-23 19 views
18

Estoy intentando aprender algo de Lisp (Common Lisp) últimamente, y me pregunto si hay alguna manera de dar un nombre constante a los números como lo puedes hacer en C a través de enumeraciones.Common Lisp equivalente a C enums

No necesito el conjunto completo de enumeraciones. Al final, solo quiero tener el código legible y.

He intentado con funciones globales y pequeñas, pero eso siempre viene con una degradación en el rendimiento. Solo conectar los números al código siempre fue más rápido.

Respuesta

22

La forma normal de hacer las enumeraciones en Lisp es el uso de símbolos . Los símbolos se internan (se reemplazan con 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, ¿dónde en C puede escribir:

 
enum { 
    apple, 
    orange, 
    banana, 
}; 

En Lisp sólo puede utilizar 'apple, y 'orange'banana directamente.

Si necesita un enumerado tipo, a continuación, se puede definir una con deftype:

(deftype fruit() '(member apple orange banana))

y luego se puede utilizar el tipo de fruit en declare, typep, typecase y así sucesivamente, y se puede escribir funciones genéricas que se especialicen en ese tipo.

+4

Sí, pero es mejor usar palabras clave. – kmkaplan

+0

Ese es un buen punto: al usar la palabra clave, evita tener que preocuparse sobre en qué paquete están sus símbolos. –

+0

En realidad, las funciones genéricas solo pueden especializarse en clases, no en tipos arbitrarios. –

6

enumeraciones son redundantes para Lisp, la razón es que todos los símbolos son su propia identidad, por lo que sólo puede utilizar aquellos, por ejemplo:

[[email protected]:~]$ clisp -q 
[1]> (setf x 'some) ;' 
SOME 
[2]> (eq x 'some) ;' 
T 
[3]> 
15

Por ejemplo, usted desea asignar un nombre tamaños de fuente:

(defconstant +large+ 3) 
(defconstant +medium+ 2) 
(defconstant +small+ 1) 

Se puede escribir una macro para hacerlo más corto.

Las definiciones sobre constante 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 símbolos de palabra clave:: grande,: mediano y: pequeño.

Puede probarlos con EQ y todo lo que utiliza alguna prueba de igualdad.

(let ((size :medium)) 
    (ecase size 
    (:small ...) 
    (:medium ...) 
    (:large ...))) 

También puede escribir métodos para ello:

(defmethod draw-string (message x y (size (eql :large))) ...) 

Como se ha mencionado que podría definir un tipo de conjunto:

(deftype size() '(member :small :medium :large)) 

entonces usted puede comprobar si algo es o bien de los que:

(let ((my-size :medium)) 
    (check-type my-size size)) 

Above would señalizar 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 debe crear objetos como aquí:

(make-instance 'vehicle :width :large) 

Algunas implementaciones de Common Lisp comprobarán cuando se establece la ranura hasta cierto 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: utilice 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).

+1

Las constantes numéricas (a diferencia de las palabras clave) también pueden ser útiles si desea mantener Grandes arreglos de cosas, como en un modelo mundial para un juego o simulación. Su "mapa de ocupación" podría hacer un seguimiento compacto y eficiente de diferentes tipos de cosas, como muros, monstruos y tesoros. Intervalos de constantes se pueden usar para clasificar entidades, como en '(defun monstruo-p (x) (y (> = x + menos-número-monstruo +) (<= x + mayor-número-monstruo +)))' –

+0

Dado las llamadas 'defconstant' anteriores, mezcladas con los ejemplos posteriores de uso de palabras clave, me parece que uno podría mezclar estos dos y tener algo como lo siguiente cuando se pasa al código que no es lisp:' (defun size-number (tamaño) (tamaño de tamaño de cheque) (caso (: pequeño + pequeño +) (: medio + medio +) (: grande + grande +))) '. O tal vez uno se salta el 'check-type' y usa' ecase' en lugar de 'case'. Un '' number-to-size '' recíproco podría escribirse de manera similar. – lindes