2011-11-13 12 views
5

Estoy tratando de escribir una función Lisp que pueda tomar argumentos opcionales y de palabras clave. La función comienza¿Cómo puedo tener argumentos opcionales Y argumentos de palabras clave para la misma función?

(defun max-min (v &optional max min &keyword (start 0) (end nil)) 

Cuando intento llamar a la función usando los argumentos de la palabra clave pero no los opcionales, obtengo un error. Lo que estoy tratando de hacer es

(max-min #(1 2 3 4) :start 1 :end 2) 

estoy recibiendo el error Error: :START' is not of the expected type REAL'

Asumo que esto se debe a que está tratando de obligar a :startmax. ¿Cómo puedo hacer que esto funcione? Gracias.

Respuesta

8

Debe llamar a esa función con el parámetro requerido, los parámetros opcionales y luego los parámetros de palabra clave. ¿Cómo debería funcionar de otra manera? Su llamada carece de los parámetros opcionales. Si desea especificar parámetros de palabra clave en la llamada, los opcionales ya no son opcionales.

(max-min #(1 2 3 4) 0 100 :start 1 :end 2) 

La regla de estilo básico:

No mezcle opcional con parámetros de palabras clave en una función. Common Lisp, por ejemplo, lo usa en algún lugar y es una fuente de errores.

CL:READ-FROM-STRING es un ejemplo.

read-from-string string 
       &optional eof-error-p eof-value 
       &key start end preserve-whitespace 

http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_fro.htm

Esto funciona:

(read-from-string " 1 3 5" t nil :start 2) 

Esto puede funcionar también:

(read-from-string " 1 3 5" :start 2) 

Pero el usuario olvidó de especificar el EOF-ERROR-P y EOF-VALOR . El compilador de Lisp no se queje y el usuario se preguntará por qué no se iniciará a 2.

5

Para completarlo, puede técnicamente conseguir que funcione mediante el análisis de la lista de argumentos proporcionados a sí mismo:

(defun max-min (v &rest args) 
    (flet ((consume-arg-unless-keyword (default) 
      (if (keywordp (first args)) 
       default 
       (pop args)))) 
    (let ((max (consume-arg-unless-keyword nil)) 
      (min (consume-arg-unless-keyword nil))) 
     (destructuring-bind (&key (start 0) (end nil)) args 
     ;; ... 
     )))) 

Como siempre, sin embargo, es una buena idea escuchar a Rainer. Esto parece un diseño demasiado mágico. Confunde tanto el entorno de desarrollo (por ejemplo, la visualización automática de arglist) como el usuario (al hacer que los errores de tipo sean más difíciles de encontrar: ¿qué sucede cuando pasas accidentalmente una palabra clave donde intentas pasar un número?).

Cuestiones relacionadas