我读了SICP的第4章,刚刚发现第一节列出了实现评估器最重要的功能,
eval
和apply
,我明白eval
非常重要,但是为什么apply
是很重要?对于某些语言,完全没有 apply
,例如 Javascript。
编辑:抱歉,我错误地认为 JavaScript 中没有适用,请忽略它。
SICP(和其他地方)中的评估/应用将评估器的两个主要部分分开。第一部分,即
eval
正在做的部分,正在处理代码到其含义的语法翻译——但除了分派表达式类型之外,它几乎没有做任何事情。正如你在书中看到的,各种“特殊形式”都有不同的eval-foo
,因为每种形式都有自己独特的评估规则。
现在,评估者需要处理的最重要的形式是函数应用。事实上,这一点非常重要,以至于这种形式没有关键字(否则,你会看到
apply
或任何乱七八糟的方案/lisp 代码)。相反,如果一个表单以不是已知特殊形式的东西开始(并且在实际实现中,不是已知宏),则求值器将其视为函数应用程序。此时,要评估函数调用,您需要评估函数本身(第一种形式)及其所有参数,然后需要将第一个值应用于其余值。这里的一个主要启发时刻是认识到 eval
和 apply
之间存在重大区别 - 前者本质上处理 syntax,但后者处理 values。 顺便说一句,有几个人将其与Scheme 和 Lisp 实现所具有的内置
apply
函数混淆了。为什么该函数需要在语言中,与 SICP 点完全无关(粗略地说,它提供了没有它就无法实现的功能,它是从实现到语言的一种反射形式)。我什至认为 SICP 评估者甚至没有在解释语言中提供
apply
。如果您正在寻找更多启发,那么这样做(使用 SICP 元循环评估器,并将 apply
添加到 解释语言)将是一个很好的反思练习。
注意这里的代码:
http://mitpress.mit.edu/sicp/code/ch4-mceval.scm(死链接)
(apply fn args)
。如果您有一种支持函数调用的语言,那么您的解释器中可能会有一个 apply 函数。 Scheme 和 Javascript 之间的区别在于,Scheme 不仅向解释器公开此函数,还向正在解释的程序公开该函数。
它不具有普遍性。例如,它假设严格的语义,而语言可以延迟评估。
为了讨论某个程序是如何构造和解释的,我们需要参考它的语法。如果存在明显的可见外部语法和不可见内部语法,则描述会变得混乱。 Lisp 使它们几乎一模一样。另外,处理本身可以用相同的 Lisp 来表达。我们可以轻松地讨论语法的解释,因为它是公开的,并且我们有所有部分的名称。此外,我们可以用相同的语法编写处理
。