关于SICP的问题chpt 4.1:(analyze expr)如何帮助加速eval?

wk1*_*989 8 lisp scheme sicp

我正在阅读SICP的以下部分

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

根据文本,以下eval改进将提高性能,因为多次评估的表达式只会被分析一次?

(define (eval exp env)
    ((analyze exp) env))
Run Code Online (Sandbox Code Playgroud)

这是analyze本书中给出的函数:

(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)))))
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这本书说analyze只会运行一次.没有了身体eval,这是((analyze exp) env))基本上是说,每次eval被调用时,analyze将一个名为exp作为它的参数?这意味着analyze每次调用时eval都会调用它.

我的理解有什么问题?我将不胜感激任何反馈,谢谢!

Gin*_*kas 5

实际上,每次eval使用程序代码作为参数调用时,都会调用语法赋值器.但是,当该代码中的函数调用该代码中的另一个函数时(或者,在最简单的情况下,它通过递归调用自身),内部apply将获得分析的表达式(最后是一个lambda函数)作为参数,而不是需要再次进行语法分析才能执行的代码块.


Fre*_*Foo 5

Gintautas的回答是正确的,但也许是一个例子.假设您已经开发了一个体现循环结构的Scheme方言

(do-n-times n expr)
Run Code Online (Sandbox Code Playgroud)

具有明显的语义.现在,当你打电话给天真eval来评估一个运行十次的循环时

(eval '(do-n-times 10 (print 'hello)))
Run Code Online (Sandbox Code Playgroud)

然后它会分析循环体十次.随着版本eval,从评估分离分析,循环体是analyzeð一次,然后评估十倍.

分析阶段回送一个过程,这可能会或不会在你的方案解释快.但是,可以想见,做各种优化的(死代码分析,JIT编译成机器代码,等等).