2012-05-20 10 views
11

Después de leer mucha documentación sobre el operador Lisp eval-when, todavía no puedo entender sus usos, sé que con este operador puedo controlar el tiempo de evaluación de mis expresiones pero no puedo encontrar ningún ejemplo donde esto pueda ser aplicable.Evaluar: ¿cuándo se usa?

Saludos cordiales, utxeee.

Respuesta

21

Compilación de un fichero Lisp

Tomemos por ejemplo la compilación de un fichero Lisp. El compilador Lisp procesa los formularios de nivel superior. Estos pueden ser formas arbitrarias Lisp, Defuns, DEFMACROS, DEFCLASS, llamadas a funciones, ...

Toda la historia de cómo funciona el compilador de archivos es demasiado compleja para explicar aquí, pero algunas cosas:

  • el compilador de archivos genera código para un formulario (DEFUN foo()). Pero no ejecuta la forma difunta. Por lo tanto, durante la compilación se sabe que existe una función FOO, pero el código de 'FOO' no está disponible durante la compilación. El compilador genera el código para el archivo compilado, pero no lo guarda en la memoria. No puede llamar a dicha función en tiempo de compilación.

  • para macros esto funciona ligeramente diferente: (DEFMACRO BAZ ...). El compilador de archivos no solo compilará la macro y se dará cuenta de que está allí, sino que también hará que la macro esté disponible en el momento de la compilación. Se carga en el compilador entorno.

Así imaginar la secuencia de formas en un archivo:

(defmacro baz ...) 

(defun foo() (baz ...)) 

Esto funciona porque el compilador de archivos conoce la macro BAZ y cuando se compila el código para FOO, entonces se puede ampliar la forma de macro .

Ahora veamos el siguiente ejemplo:

(defun bar (form) ...) 

(defmacro baz (form) (bar form)) 

(defun foo() (baz ...)) 

anterior no funcionará. Ahora la macro BAZ usa la función BAR llamándola. Cuando el compilador intenta compilar la función FOO, no puede expandir la macro BAZ, porque BAR no se puede llamar, porque el código de BAR no se carga en el entorno de tiempo de compilación.

Hay dos soluciones a este:

  1. compilación y carga BAR anterior utilizando un archivo separado.
  2. Uso EVAL-WHEN

Ejemplo para EVAL-WHEN:

(eval-when (:compile-toplevel :execute :load-toplevel) 
    (defun bar (form) ...) 
) 

(defmacro baz (form) (bar form)) 

(defun foo() (baz ...)) 

Ahora el EVAL-WHEN indica al compilador archivo para ejecutar realmente la forma DEFUN durante la compilación.El efecto de esto es: el compilador de archivos ahora conoce la definición de BAR en tiempo de compilación. Por lo tanto, está disponible más adelante, cuando el compilador de archivos necesita llamar al BAR durante la expansión de macro del uso de BAZ.

Se podría usar solo :compile-toplevel, cuando la función no sería necesaria después de la compilación del archivo. Si se usa más adelante, entonces debemos asegurarnos de que se cargue.

Así EVAL-WHEN permite especificar si una determinada pieza de código se debe ejecutar

  • durante la compilación de un archivo
  • durante la carga de un archivo
  • durante la ejecución

EVAL-WHEN es no se usa tan a menudo en el código de usuario. Si lo usa, entonces debería preguntarse si realmente lo necesita.

+0

Hola Rainer, pero ¿por qué tenemos que usar los indicadores: ejecutar y: cargar-nivel superior en este uso de eval-when? – utxeee

+0

Rainer agradece nuevamente su respuesta al editar la respuesta anterior: D Pero mi duda persiste, por qué necesito usar los indicadores: load-top-level y: execute. De su texto puedo ver que deberíamos usar la bandera: load-top-level si la función se usa más tarde. Entonces, ¿por qué no necesitamos usar el eval-when con: load-top-level en todas las demás funciones que se usarán más adelante? – utxeee

+0

@utxeee: load-top-level es un valor predeterminado durante la compilación, cuando no hay EVAL-WHEN. –

Cuestiones relacionadas