2010-10-13 6 views
8

lese ich den folgenden Abschnitt von SICPFrage zu SICP chpt 4.1: Wie hilft (analysieren expr) helfen eval zu beschleunigen?

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

den Text entsprechend, wird die folgende Transformation von eval verbessern wird eine Leistungsverbesserung, da ein Ausdruck bietet, die nur einmal analysiert werden oft ausgewertet wird ?

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

Hier eine analyze Funktion in dem Buch:

(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))))) 

Ich verstehe nicht, warum das Buch sagt, dass analyze nur einmal ausgeführt werden. Nicht der Körper von eval, der ((analyze exp) env)) grundsätzlich ist, dass jedes Mal eval heißt, wird analyze mit exp als Parameter aufgerufen werden? Dies würde bedeuten, dass analyze jedes Mal aufgerufen werden würde, wenn eval aufgerufen wird.

Was ist falsch mit meinem Verständnis? Ich würde mich über jede Rückmeldung freuen, danke!

Antwort

5

Tatsächlich wird jedes Mal, wenn Sie eval mit Programmcode als Parameter aufrufen, der syntaktische Evaluator aufgerufen. Wenn jedoch eine Funktion innerhalb dieses Codes eine andere Funktion in diesem Code aufruft (oder im einfachsten Fall sich selbst durch Rekursion aufruft), erhält der innere apply den analysierten Ausdruck (der am Ende eine Lambda-Funktion ist) als Argument und nicht ein Code-Blob, der zur Ausführung syntaktisch erneut analysiert werden müsste.

5

Gintautas 'Antwort ist richtig, aber vielleicht ist ein Beispiel in Ordnung. Angenommen, Sie haben einen Scheme-Dialekt entwickelt, der ein Schleifenkonstrukt

(do-n-times n expr) 

mit der offensichtlichen Semantik hat. Wenn Sie nun die naive eval rufen eine Schleife zu bewerten, die zehnmal so läuft

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

dann wird es der Schleife zehnmal analysieren. Mit der Version eval, die die Analyse von der Auswertung trennt, wird der Schleifenkörper einmal analyze d, dann zehn Mal ausgewertet.

Die Analysephase gibt eine Prozedur zurück, die in Ihrem Scheme-Interpreter möglicherweise nicht schnell genug ist. Es könnte jedoch denkbar sein, alle Arten von Optimierungen durchzuführen (tote Code-Analyse, JIT compilation, um Code zu programmieren, usw.).

2

larsmans 'Antworten sind extrem gut.

Als eine ergänzende Antwort kann man auch analyze(environ) als eine Curry-Form von eval(expr, environ) ansehen, wo der Parameter expr vor der Zeit übergeben wurde. In SICP können Sie den Beispielcode wie lesen:

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

Wenn Sie eine let (([var] [preprocessed stuff])) sehen, dass in einem Verschluss Vorverarbeitung gespeichert wird, bis sie später benötigt wird, wenn environ ist bestanden in

.