在 SICP 第 4 章中,通过将语法分析与执行分离来修改元循环求值器,使eval
过程如下所示:
(define (eval exp env)
((analyze exp) env))
并且书中说这将节省工作,因为analyze
将在表达式上调用一次,而执行过程可能会被调用多次。
我的问题是,这种优化是如何工作的?它适用于递归过程调用,但其他情况呢?评估器一个接一个地评估表达式,eval
即使它们具有相同的形式,仍然会在每个表达式上被调用。
你需要看到几件事情:(a)analyze
函数只遍历每个表达式一次,(b) 没有analyze
扫描语法之外的代码,(c) 函数analyze
返回的函数不会调用自身,因此运行该函数永远不会导致对于语法的任何进一步扫描,(d) 这完全不同于通常的评估函数,其中调用一个函数两次意味着它的语法被扫描了两次。
顺便说一句,一个更好的名字analyze
是compile
——它确实将输入语言(sexprs)翻译成目标语言(一个函数,在这里充当机器代码)。
编译器和解释器的区别在于:
编译器只扫描您的源代码一次并将其更改为执行代码(可能是机器代码)。下次执行程序时,直接执行执行代码,不分析源代码,效率高。
但是,每次执行程序时,解释器都会分析源代码。
这种优化仅在您的程序将被多次执行的情况下才有意义。
正如@Eli Barzilay 所说,“一个更好的名称analyze
是compile
”,您分析的函数就像执行代码。递归函数就像会被多次执行的程序。
analyze
只需进行一次语法分析,并将转换后的等存储definition
在环境中,在lookup-variable-value
执行相关过程时可以直接使用。
相比之下,原始的元循环评估器扭曲了语法分析和执行,这使得每次执行也调用了语法分析。
此链接可能有帮助: http ://www.cs.brandeis.edu/~mairson/Courses/cs21b/Handouts/feeley-notes.pdf