规避 SCHEME 中的 EVAL

发布于 2024-07-25 16:08:00 字数 237 浏览 5 评论 0原文

彼得·诺维格 (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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

∞梦里开花 2024-08-01 16:08:00

在某些情况下,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 avoiding eval except for ... eval.

(BTW, my guess is that PAIP was written a long time ago, before eval was added to the Scheme Report.)

Hello爱情风 2024-08-01 16:08:00

他错了。 当然Scheme中有eval

He's wrong. Of course there is eval in Scheme.

上课铃就是安魂曲 2024-08-01 16:08:00

在某些非常罕见的情况下,您将需要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. Having eval 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.

雄赳赳气昂昂 2024-08-01 16:08:00

至少对于最新版本的Scheme 标准(R5RS 及更高版本)来说,Scheme 没有eval 的说法是不准确的。 通常,您需要的是一个宏,它将在编译时生成代码。

确实应该避免eval。 对于初学者来说,我从未见过关于它应该如何表现的令人满意的定义,例如:

  1. 当没有传递环境时应该评估什么环境表达式?
  2. 当你确实经过一个环境时,它们是如何工作的? 例如,标准没有指定您可以在该环境对象中预先绑定值的方式。

也就是说,我使用过一个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:

  1. What environment expressions should be evaluated in when no environment is passed?
  2. When you do pass in an environment, how do those work? For example, the standards specify no way you can pre-bind a value in that environment object.

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 never eval anything that doesn't have a huge wall of separation from user input. Basically, if you want to use eval 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!).

谜泪 2024-08-01 16:08:00

首先,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 using eval 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 about goto, although they're quite useful in some restricted circumstances, but most goto use is by people who don't know any better.

时光匆匆的小流年 2024-08-01 16:08:00

我在脚本环境中看到“eval”的一种用途是使用运行时值参数化某些代码。 例如,在伪-C 中:

param = read_integer();
fn = eval("int lambda(int x) { 
            int param = " + to_string(param) + "; 
            return param*x; }");

我希望你觉得它真的很难看。 字符串粘贴以在运行时创建代码? 恶心。 在Scheme和其他词法作用域的Lisp中,您可以在不使用eval的情况下创建参数化函数。

(define make-my-fn
  (lambda (param)
    (lambda (x)  (* param x)))

(let* ([ param  (read-integer) ]
       [ fn     (make-my-fn param ])
  ;; etc.
 )

就像前面提到的,动态代码加载等仍然需要 eval,但是参数化代码和代码组合可以使用一流函数生成。

One use I've seen for 'eval' in scripting environments is to parameterize some code with runtime values. for instance, in psuedo-C:

param = read_integer();
fn = eval("int lambda(int x) { 
            int param = " + to_string(param) + "; 
            return param*x; }");

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.

(define make-my-fn
  (lambda (param)
    (lambda (x)  (* param x)))

(let* ([ param  (read-integer) ]
       [ fn     (make-my-fn param ])
  ;; etc.
 )

Like was mentioned, dynamic code loading and such still need eval, but parameterized code and code composition can be produced with first class functions.

酒与心事 2024-08-01 16:08:00

您可以在方案中编写一个方案解释器。 这当然是可能的,但不切实际。

当然,这是一个一般性的答案,因为我没有使用过的方案,但它仍然可以帮助你。 :)

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. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文