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

时间:2010-10-13 20:55:07

标签: lisp scheme sicp

我正在阅读SICP的以下部分

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

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

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

这是本书中给出的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)))))

我不明白为什么这本书说analyze只运行一次。 eval ((analyze exp) env))的正文基本上不是每次调用evalanalyze都会以exp作为参数调用analyze ?这意味着每次调用eval时都会调用{{1}}。

我的理解有什么问题?我要感谢任何反馈,谢谢!

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

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

(do-n-times n expr)

具有明显的语义。现在,当您调用天真eval来评估一个运行十次的循环时

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

然后它会分析循环体十次。使用eval版本将分析与评估分开,循环体为analyze d一次,然后评估十次。

分析阶段会返回一个过程,该过程在您的Scheme解释器中可能会或者不会很快。但是,可以想象它可以进行各种优化(死代码分析,机器代码JIT compilation等)。

答案 2 :(得分:2)

larsmans的答案非常好。

作为补充答案,您还可以将analyze(environ)视为eval(expr, environ)的咖喱形式,其中参数expr已提前传递。在SICP中,您可以阅读示例代码,如:

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

当您看到let (([var] [preprocessed stuff]))时,预处理存储在闭包中,直到稍后在传递environ时需要它。