Lisp 关于SICP chpt 4.1的问题:分析expr如何帮助加快评估?

Lisp 关于SICP chpt 4.1的问题:分析expr如何帮助加快评估?,lisp,scheme,sicp,Lisp,Scheme,Sicp,我正在阅读SICP的以下部分 根据本文,以下对eval的转换将提高性能,因为一个表达式经过多次求值,只能分析一次 (define (eval exp env) ((analyze exp) env)) 这是本书中给出的分析函数: (define (analyze-if exp) (let ((pproc (analyze (if-predicate exp))) (cproc (analyze (if-consequent exp))) (aproc (ana

我正在阅读SICP的以下部分

根据本文,以下对
eval
的转换将提高性能,因为一个表达式经过多次求值,只能分析一次

(define (eval exp env)
    ((analyze exp) env))
这是本书中给出的
分析
函数:

(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))
是否基本上说,每次调用
eval
时,
analyze
都将以
exp
作为参数进行调用?这意味着每次调用
eval
时都会调用
analyze


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

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

Gintautas的答案是正确的,但也许有一个例子是正确的。假设您已经开发了一个使用循环构造的Scheme方言

(do-n-times n expr)
具有明显的语义。现在,当您调用naive
eval
来计算一个运行十次的循环时

(eval '(do-n-times 10 (print 'hello)))
然后,它将对环体进行十次分析。使用将分析与评估分离的
eval
版本,循环体是
analyze
d一次,然后评估十次


分析阶段返回一个过程,该过程在Scheme解释器中可能很快,也可能不快。然而,它可以进行各种优化(死代码分析、机器代码等)。

拉斯曼的答案非常好

作为补充答案,还可以将
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
时需要它