2010-10-13 4 views
8

estoy leyendo la siguiente sección de SICPPregunta sobre SICP, capítulo 4.1: ¿Cómo ayuda (analice expr) a acelerar la evaluación?

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-26.html#%_sec_4.1.7

Según el texto, la siguiente transformación de eval mejorará ofrece una mejora de rendimiento, ya que una expresión que obtenga evaluado muchas veces sólo se analizó una vez ?

(define (eval exp env) 
    ((analyze exp) env)) 

Aquí es una función analyze dada en el libro:

(define (analyze-if exp) 
(let ((pproc (analyze (if-predicate exp))) 
    (cproc (analyze (if-consequent exp))) 
     (aproc (analyze (if-alternative exp)))) 
    (lambda (env) 
     (if (true? (pproc env)) 
      (cproc env) 
       (aproc env))))) 

No entiendo por qué el libro dice que analyze sólo se ejecutará una vez. ¿No es el cuerpo de eval, que es ((analyze exp) env)) decir básicamente que cada vez que se llama eval, se llamará analyze con exp como su parámetro? Esto significa que se llamaría al analyze cada vez que se llame a eval.

¿Qué hay de malo en mi entendimiento? Agradecería cualquier comentario, ¡gracias!

Respuesta

5

De hecho, cada vez que llame al eval con un código de programa como parámetro, se invocará el evaluador sintáctico. Sin embargo, cuando una función dentro de ese código llama a otra función dentro de ese código (o, en el caso más simple, se llama por recurrencia), el apply interno obtendrá la expresión analizada (que al final es una función lambda) como argumento , en lugar de una burbuja de código que debería analizarse sintácticamente de nuevo para poder ejecutarse.

5

La respuesta de Gintautas es correcta, pero tal vez sea un buen ejemplo. Supongamos que ha desarrollado un dialecto de esquema que tiene una construcción de bucle

(do-n-times n expr) 

con la semántica obvia. Ahora, cuando se llama a la ingenua eval para evaluar un bucle que se ejecuta diez veces

(eval '(do-n-times 10 (print 'hello))) 

continuación, se analizará el cuerpo del bucle diez veces. Con la versión de eval que separa el análisis de la evaluación, el cuerpo del ciclo es analyze d una vez, luego se evalúa diez veces.

La fase de análisis devuelve un procedimiento, que puede o no ser rápido en su intérprete de Scheme. Sin embargo, es concebible que realice todo tipo de optimizaciones (análisis de código muerto, JIT compilation a código de máquina, etc.).

2

las respuestas de larsmans son extremadamente buenas.

Como respuesta complementaria, también se puede ver analyze(environ) como una forma curry de eval(expr, environ) donde el parámetro expr se ha pasado antes de tiempo. En SICP, se puede leer el código de ejemplo como:

(define (analyze-assignment exp) 
    (let ((var (assignment-variable exp)) 
     (vproc (analyze (assignment-value exp)))) 
    (lambda (env) 
     (set-variable-value! var (vproc env) env) 
     'ok))) 

Cuando vea un let (([var] [preprocessed stuff])), que se preprocesamiento de almacenarse en un cierre hasta que se necesite más tarde, cuando se pasa en environ

.