2012-02-20 10 views
8

Estoy escribiendo algunos métodos para emitir HTML para varios elementos. Cada método tiene el mismo resultado, pero no necesariamente necesita la misma entrada.Argumentos opcionales en defgeneric?

El método para Haciéndose eco de un game-board necesidades para tomar una player también (debido a que cada jugador sólo ve sus propias piezas)

(defmethod echo ((board game-board) (p player)) ...) 

Haciéndose eco de un espacio en la placa No es necesario cambiar por jugador (que es en realidad el envío hecho en el método game-board, que más tarde llama al echo en un espacio). Idealmente, me gustaría ser capaz de hacer

(defmethod echo ((space board-space)) ...) 
(defmethod echo ((space empty-space)) ...) 

También es concebible que más tarde me encuentro con un objeto que se necesita saber más que el jugador con el fin de mostrar por sí mismo adecuadamente. Dado que ya hay métodos que se especializan en el mismo genérico, sin embargo, que darían el error

The generic function #<STANDARD-GENERIC-FUNCTION ECHO (4)> takes 2 required arguments; 

Parece menos que ideal para volver y nombrar estos métodos echo-space, echo-board y así sucesivamente.

¿Existe alguna manera canónica de variar otros argumentos basados ​​en el objeto especializado? ¿Debo hacer algo como

(defgeneric echo (thing &key player ...) ...) 

o

(defgeneric echo (thing &rest other-args) ...) 

? De manera más general, ¿alguien puede indicarme un tutorial decente en defgeneric específicamente? (He leído los capítulos PCL relevantes y some CLOS tutorials, pero no cubren la situación que estoy preguntando aquí).

Respuesta

5

En general, si las interfaces de dos funciones son demasiado diferentes, indica que no son en realidad una especialización de la misma operación y no deberían tener el mismo nombre. Si solo desea especializarse en argumentos opcionales/clave, la forma de lograr eso es usar una función normal que llame a una función genérica y le proporcione valores predeterminados para los argumentos faltantes para especializarse.

Keene's book es, creo, la guía más completa de CLOS. Lamentablemente, parece estar disponible solo en forma de libro.

+0

Tener un despacho de función en un genérico parece poco satisfactorio (eso me llevaría de regreso a 'eco-board' /' echo-space'/etc. Territory). Creo que tienes razón en este caso; Sería mejor que definiera algo como 'echo' (para producir elementos individuales ingenuamente) y un' echo-tailored' separado (o similar) (que cambiaría su salida en función de parámetros adicionales). – Inaimathi

+0

La función no genérica no despacha, simplemente canonicaliza los argumentos. Obviamente, esto requiere que los métodos genéricos (y los métodos) tomen todos los argumentos posibles, por lo que esto es útil solo cuando la interfaz es realmente similar. – Ramarren

+0

Aquí hay un PDF del libro de Keene (no sé qué tan legal es esto, por favor asesorar): https://doc.lagout.org/programmation/Lisp/Object-Oriented%20Programming%20in%20Common%20Lisp_% 20A% 20Programador% 27s% 20Guía% 20to% 20CLOS% 20% 5BKeene% 201989-01-11% 5D.pdf –

0

¿Qué hay de la reestructuración de los objetos/clases para que cada objeto que desea hacer eco tenga todas las propiedades requeridas en sus propios espacios (y heredados)?

De esta forma, no tiene que pasarlos como argumentos cuando llama a echo en el objeto, ya que lo que necesita ya está almacenado en el objeto.

3

Es más fácil cuando los métodos toman los mismos parámetros pero solo difieren en el tipo de datos. Pero en los casos donde la función y los métodos genéricos usan el mismo nombre (por supuesto) pero tienen listas lambda que varían significativamente, yo personalmente tiendo a usar los parámetros clave & para hacer explícitas mis intenciones, en vez de usar los parámetros opcionales &. Creo que ayuda con la legibilidad más tarde.

Pruebe algo como esto (pretendiendo que ya tenemos clases de clase A y clase B):

(defgeneric foo (object &key &allow-other-keys) 
    (:documentation "The generic function. Here is where the docstring is defined.")) 

(defmethod foo ((object class-a) &key &allow-other-keys) 
    (print "Code goes here. We dispatched based on type Class A.")) 

(defmethod foo ((object class-b) &key (x 1) (y 2) &allow-other-keys) 
    (print "Code goes here. We dispatched based on type Class B. We have args X and Y.")) 

Desde "combinación de método" participa, a fin de que la lógica de despacho de "flujo" a través de su Posibles opciones de métodos para usar, necesitamos pensar en las definiciones de métodos como una cadena donde las listas lambda incompatibles (es decir, las listas de parámetros) romperán esa cadena. Es por eso que existe la clave & y & allow-other-keys en las definiciones de métodos que no las necesitan específicamente. Poniéndolos en DEFGENERIC y las definiciones del método nos permite tener la definición del método donde despachamos en base a la clase-b.

DESCARGO DE RESPONSABILIDAD: Soy un novato de Common Lisp, así que tómalo con un grano de sal!

Cuestiones relacionadas