规避 SCHEME 中的 EVAL
彼得·诺维格 (Peter Norvig) 在 PAIP 中说道:
在现代 lisps 中...eval 很少被使用(事实上,在Scheme 中有 根本没有评估)。 如果您发现自己使用 eval,那么您可能是 做错事
有哪些方法可以避免在方案中使用 eval
? 是否存在绝对需要 eval
的情况?
Peter Norvig in PAIP says:
in modern lisps...eval is used less often (in fact, in Scheme there is
no eval at all). If you find yourself using eval, you are probably
doing the wrong thing
What are some of the ways to circumvent using eval
in scheme? Arent there case where eval
is absolutely necessary?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
在某些情况下,
eval
是必要的,但它们总是涉及高级程序,例如动态加载某些代码(例如,Web 服务器中的 servlet)。 至于“规避”使用它的方法 - 这取决于您要解决的实际问题,没有什么神奇的解决方案可以避免eval
除了...eval
代码>.(顺便说一句,我的猜测是 PAIP 是很久以前写的,在
eval
添加到方案报告之前。)There are cases where
eval
is necessary, but they always involve advanced programs that do things like dynamically loading some code (eg, a servlet in a web server). As for a way to "circumvent" using it -- that depends on the actual problem you're trying to solve, there's no magic solution to avoidingeval
except for ...eval
.(BTW, my guess is that PAIP was written a long time ago, before
eval
was added to the Scheme Report.)他错了。 当然Scheme中有
eval
。He's wrong. Of course there is
eval
in Scheme.在某些非常罕见的情况下,您将需要
eval
。 首先想到的情况是当您用程序构建程序然后执行它时。 例如,这主要发生在遗传算法中。 在这种情况下,您将构建许多需要执行的随机程序。 将eval
与作为数据的代码结合起来,使 Lisp 成为执行遗传算法的最简单的编程语言。拥有这些属性需要付出巨大的代价(就程序的速度和大小而言),因为您将消除对将要评估的代码进行编译时优化的所有可能性,并且必须将完整的解释器保留在生成的二进制文件中。
因此,在可以避免的情况下使用
eval
被认为是糟糕的设计。You'll need
eval
in some very rare case. The case that comes into mind first is when you'll build program with a program and then execute it. This happens mainly with genetic algorithm for example. In this case you build a lot a randomized programs that you'll need to execute. Havingeval
in conjunction with code being data make lisp the easiest programming language to do genetic algorithm.Having these properties comes at a great cost (in term of speed and size of your program) because you'll remove all possibility to do compile time optimization on the code that will be evaled and you must keep the full interpreter in your resulting binary.
As a result it is considered poor design to use
eval
when it can be avoided.至少对于最新版本的Scheme 标准(R5RS 及更高版本)来说,Scheme 没有
eval
的说法是不准确的。 通常,您需要的是一个宏,它将在编译时生成代码。确实应该避免
eval
。 对于初学者来说,我从未见过关于它应该如何表现的令人满意的定义,例如:也就是说,我使用过一个Scheme 应用程序,该应用程序使用
eval
在运行时动态生成代码,以应对在编译时无法知道计算结构的情况。 出于性能原因,其目的是让Scheme 系统在运行时编译代码,困难在于没有标准方法告诉Scheme 系统“编译此代码”。不言而喻,
eval
可能会带来巨大的安全风险。 您永远不应该评估
任何与用户输入没有巨大隔离墙的东西。 基本上,如果您想安全地使用eval
,您应该在解析一些输入(使用全面定义的语法!)。The claim that Scheme has no
eval
is inaccurate at least for the most recent versions of the Scheme standard (R5RS and later). Usually, what you want is a macro instead, which will generate code at compilation time.It is true that
eval
should be avoided. For starters, I've never seen a satisfactory definition of how should it behave, for example:That said, I've worked with a Scheme application that uses
eval
to generate code dynamically at runtime for cases where the structure of the computation cannot be known at compilation time. The intent has been to get the Scheme system to compile the code at runtime for performance reasons—and the difficulty is that there is no standard way to tell a Scheme system "compile this code."It should go without saying also that
eval
can be a huge security risk. You should nevereval
anything that doesn't have a huge wall of separation from user input. Basically, if you want to useeval
safely, you should be doing so in the context of the code-generation phase of a compiler-like system, after you've parsed some input (using a comprehensively defined grammar!).首先,PAIP是为Common Lisp而不是Scheme编写的,所以我不知道他会说同样的话。 CL 宏与
eval
执行的操作大致相同,不过是在编译时而不是运行时执行,并且您还可以执行其他操作。 如果您向我展示一个在 Common Lisp 中使用eval
的示例,我可以尝试想出其他方法来完成同样的事情。我不是一名计划程序员。 我只能从 Norvig 作为一名 Common Lisp 程序员的角度来谈谈。 我认为他不是在谈论Scheme,也不知道他是否了解或者特别了解Scheme。
其次,诺维格说“你可能做错了事”,而不是“你正在做错事”。 这意味着,据他所知,有时
eval
是正确的使用方法。 在像 C 这样的语言中,我会对goto
说同样的话,尽管它们在某些受限情况下非常有用,但大多数goto
使用的是那些不使用 goto 的人不知道有什么更好的。First, PAIP is written for Common Lisp, not Scheme, so I don't know that he'd say the same thing. CL macros do much the same thing as
eval
, although at compile time instead of run time, and there's other things you could do. If you'd show me an example of usingeval
in Common Lisp, I could try to come up with other methods of doing the same thing.I'm not a Scheme programmer. I can only speak from Norvig's perspective, as a Common Lisp programmer. I don't think he was talking about Scheme, and I don't know if he knew or knows Scheme particularly well.
Second, Norvig says "you are probably doing the wrong thing" rather than "you're doing the wrong thing". This implies that, for all he knows, there's times when
eval
is the correct thing to use. In a language like C, I'd say the same thing aboutgoto
, although they're quite useful in some restricted circumstances, but mostgoto
use is by people who don't know any better.我在脚本环境中看到“eval”的一种用途是使用运行时值参数化某些代码。 例如,在伪-C 中:
我希望你觉得它真的很难看。 字符串粘贴以在运行时创建代码? 恶心。 在Scheme和其他词法作用域的Lisp中,您可以在不使用eval的情况下创建参数化函数。
就像前面提到的,动态代码加载等仍然需要 eval,但是参数化代码和代码组合可以使用一流函数生成。
One use I've seen for 'eval' in scripting environments is to parameterize some code with runtime values. for instance, in psuedo-C:
I hope you find that really ugly. String pasting to create code at runtime? Ick. In Scheme and other lexically scoped Lisps, you can make parameterized functions without using eval.
Like was mentioned, dynamic code loading and such still need eval, but parameterized code and code composition can be produced with first class functions.
您可以在方案中编写一个方案解释器。 这当然是可能的,但不切实际。
当然,这是一个一般性的答案,因为我没有使用过的方案,但它仍然可以帮助你。 :)
You could write a scheme interpreter in scheme. Such is certainly possible, but it is not practical.
Granted, this is a general answer, as I have no used scheme, but it may help you nonetheless. :)