为什么 apply 对于 Lisp 评估器如此重要?
我已经阅读了SICP的第4章,刚刚发现第一节列出了实现评估器最重要的函数,eval
和apply
,我明白eval
非常重要,但是为什么apply
如此重要呢?对于某些语言,完全没有apply
,例如Javascript。
编辑:抱歉,我错误地认为 JavaScript 中没有适用,请忽略它。
I have read chapter 4 of SICP, and just found that the first section lists the most important functions for implementing a evaluator, eval
and apply
, I understand that eval
is very important, but why apply
is so important? For some language, there is totally no apply
such as in Javascript.
Edit: Sorry about that I am wrong about there is no apply in Javascript, please just ignore that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
SICP(以及其他地方)中的 eval/apply 部分将评估器的两个主要部分分开。第一部分,即 eval 正在做的部分,是处理代码到其含义的语法翻译——但除了分派表达式类型之外,它几乎不做任何事情。正如你在书中所看到的,对于各种“特殊形式”有不同的
eval-foo
,因为它们都有自己独特的评估规则。现在,评估者需要处理的最重要的形式是函数应用。事实上,这一点非常重要,以至于这种形式没有关键字(否则,您会看到
apply
或任何乱七八糟的方案/lisp 代码)。相反,如果一个表单以不是已知特殊形式的东西开始(并且在实际实现中,不是已知宏),则求值器将其视为函数应用程序。此时,要评估函数调用,您需要评估函数本身(第一种形式)及其所有参数,然后需要将第一个值应用于其余值。这里的一个主要启发时刻是认识到此eval
和apply
之间存在重大区别 - 前者本质上处理语法,但是后者涉及值。附带说明一下,一些人将其与Scheme 和Lisp 实现所具有的内置
apply
函数混淆了。为什么该函数需要在语言中,与 SICP 点完全无关(粗略地说,它提供了没有它就无法实现的功能,它是从实现到语言的一种反射形式)。我什至认为 SICP 评估者甚至没有使apply
在解释语言中可用。如果您正在寻找更多启发,那么这样做(使用 SICP 元循环评估器,并将apply
添加到解释语言)将是一个很好的反思练习。The eval/apply thing in SICP (and elsewhere) is separating two major parts of an evaluator. The first part, the one that
eval
is doing, is dealing with the syntactic translation of code to its meaning -- but it's doing almost nothing except dispatching over the expression type. As you can see in the book, there are variouseval-foo
s for various "special forms", since each of them has its own unique evaluation rule.Now, the most important form that the evaluator needs to deal with is function application. In fact, it's so important that there is no keyword for this form (otherwise, you'd see
apply
or whatever littering scheme/lisp code). Instead, if a form begins with something that is not a known special form (and in real implementations, not a known macro) then the evaluator takes it to be a function application. At this point, to evaluate a function call, you need to evaluate the function itself (the first form) and all of its arguments, and then you need to apply the first value over the rest. A major enlightenment moment here is to realize that there is a major difference between thiseval
andapply
-- the former inherently deals with syntax, but the latter deals with values.As a side note, several people confused this with the built-in
apply
function that Scheme and Lisp implementation have. Why that function needs to be in the language is completely unrelated to the SICP point (roughly, it provides functionality that you cannot implement without it, it is a form of reflection from the implementation into the language). I don't even think that the SICP evaluators even makeapply
available in the interpreted language. If you're looking for more enlightenment, doing that (taking a SICP meta circular evaluator, and addingapply
to the interpreted language) will be a nice exercise in reflection.Apply 评估函数调用。它需要一个函数和一个参数列表:
(apply fn args)
。如果您有一种支持函数调用的语言,那么您的解释器中可能会有一个 apply 函数。 Scheme 和 Javascript 之间的区别在于,Scheme 不仅向解释器公开此函数,还向正在解释的程序公开该函数。Apply evaluates a function call. It takes a function and a list of arguments:
(apply fn args)
. If you have a language that supports function calls, you're probably going to have an apply function in your interpreter. The difference between Scheme and Javascript is that Scheme exposes this function not only to the interpreter, but also to the program that is being interpreted.这是在表达式上运行函数的方式,也称为将函数“应用”到表达式。
请注意此处的代码:
http://mitpress.mit.edu/sicp/code/ch4-mceval.scm(死链接)It's how you run a function on an expression, aka 'apply' the function to the expression.
Note the code here:
http://mitpress.mit.edu/sicp/code/ch4-mceval.scm(dead link)它不是通用的。例如,它假设严格的语义,而语言可以被延迟评估。
然而,基于 Lisp 的概念表示消除了大多数语法问题,因此几乎不会干扰纯粹的语义。
为了讨论某个程序是如何构造和解释的,我们需要参考它的语法。如果存在明显的可见外部语法和不可见内部语法,则描述会变得混乱。 Lisp 使它们几乎一模一样。另外,处理本身可以用相同的 Lisp 来表达。我们可以轻松地讨论语法的解释,因为它是公开的,并且我们有所有部分的名称。此外,我们可以用相同的语法编写处理。
It isn't universal. For instance, it assumes strict semantics, whereas languages can be lazily evaluated.
However, the Lisp-based representation of the concept eliminates most issues of syntax, so that there are few distractions away from the bare semantics.
In order to talk about how some program is structured and interpreted, we need to refer to its syntax. If there is a distinct outer syntax which is visible, and an invisible inner syntax, the description becomes muddled. Lisp makes them almost one and the same. Plus, the processing itself is expressible in the same Lisp. We can easily talk about the interpretation of the syntax, since it is laid bare, and we have names for all the parts. Moreover, we can write the processing in that same syntax.