为什么 eval 是邪恶的? [英] Why exactly is eval evil?

查看:21
本文介绍了为什么 eval 是邪恶的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 Lisp 和 Scheme 程序员通常会说除非绝对必要,否则应该避免使用 eval.我已经看到对几种编程语言的相同建议,但我还没有看到反对使用 eval 的明确论据列表.我在哪里可以找到使用 eval 的潜在问题的说明?

I know that Lisp and Scheme programmers usually say that eval should be avoided unless strictly necessary. I’ve seen the same recommendation for several programming languages, but I’ve not yet seen a list of clear arguments against the use of eval. Where can I find an account of the potential problems of using eval?

例如,我知道GOTO在过程编程中的问题(使程序不可读且难以维护,使安全问题难以发现等),但我从未见过反对的论点eval.

For example, I know the problems of GOTO in procedural programming (makes programs unreadable and hard to maintain, makes security problems hard to find, etc), but I’ve never seen the arguments against eval.

有趣的是,针对 GOTO 的相同论点应该对延续有效,但我看到,例如,Schemers 不会说延续是邪恶的"——你应该小心使用它们.他们更可能不喜欢使用 eval 的代码而不是使用延续的代码(据我所知——我可能是错的).

Interestingly, the same arguments against GOTO should be valid against continuations, but I see that Schemers, for example, won’t say that continuations are "evil" -- you should just be careful when using them. They’re much more likely to frown upon code using eval than upon code using continuations (as far as I can see -- I could be wrong).

推荐答案

不应该使用 EVAL 的原因有几个.

There are several reasons why one should not use EVAL.

初学者的主要原因是:你不需要它.

示例(假设为 Common Lisp):

Example (assuming Common Lisp):

使用不同的运算符评估表达式:

EVALuate an expression with different operators:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (eval (list op 1 2 3)))))

最好写成:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (funcall op 1 2 3))))

在很多例子中,学习 Lisp 的初学者认为他们需要 EVAL,但他们并不需要它——因为表达式会被求值,而且还可以对函数部分进行求值.大多数情况下,EVAL 的使用表明对评估者缺乏了解.

There are lots of examples where beginners learning Lisp think they need EVAL, but they don't need it - since expressions are evaluated and one can also evaluate the function part. Most of the time the use of EVAL shows a lack of understanding of the evaluator.

宏也有同样的问题.初学者经常编写宏,他们应该在哪里编写函数 - 不了解宏的真正用途,也不了解函数已经完成了这项工作.

It is the same problem with macros. Often beginners write macros, where they should write functions - not understanding what macros are really for and not understanding that a function already does the job.

使用EVAL往往是工作的错误工具,这往往表明初学者不了解通常的Lisp评估规则.

It often is the wrong tool for the job to use EVAL and it often indicates that the beginner does not understand the usual Lisp evaluation rules.

如果您认为需要 EVAL,请检查是否可以使用 FUNCALLREDUCEAPPLY 之类的东西改为使用.

If you think you need EVAL, then check if something like FUNCALL, REDUCE or APPLY could be used instead.

  • FUNCALL - 调用带参数的函数:(funcall '+ 1 2 3)
  • REDUCE - 在值列表上调用函数并合并结果:(reduce '+ '(1 2 3))
  • APPLY - 以列表为参数调用函数:(apply '+ '(1 2 3)).
  • FUNCALL - call a function with arguments: (funcall '+ 1 2 3)
  • REDUCE - call a function on a list of values and combine the results: (reduce '+ '(1 2 3))
  • APPLY - call a function with a list as the arguments: (apply '+ '(1 2 3)).

问:我真的需要 eval 还是编译器/评估器已经是我真正想要的?

Q: do I really need eval or does the compiler/evaluator already what I really want?

对于稍微高级的用户避免EVAL的主要原因:

The main reasons to avoid EVAL for slightly more advanced users:

  • 你想确保你的代码被编译,因为编译器可以检查代码中的许多问题并生成更快的代码,有时会生成更快的代码(这是因子 1000 ;-))更快的代码

  • you want to make sure that your code is compiled, because the compiler can check code for many problems and generates faster code, sometimes MUCH MUCH MUCH (that's factor 1000 ;-) )faster code

无法尽早编译已构建且需要评估的代码.

code that's constructed and needs to be evaluated can't be compiled as early as possible.

对任意用户输入进行评估会导致安全问题

eval of arbitrary user input opens up security problems

一些使用 EVAL 的评估可能发生在错误的时间并产生构建问题

some use of evaluation with EVAL can happen at the wrong time and create build problems

用一个简单的例子来解释最后一点:

To explain the last point with a simplified example:

(defmacro foo (a b)
  (list (if (eql a 3) 'sin 'cos) b))

因此,我可能想编写一个基于第一个参数使用 SINCOS 的宏.

So, I may want to write a macro that based on the first parameter uses either SIN or COS.

(foo 3 4)(sin 4)(foo 1 4)(cos 4)代码>.

(foo 3 4) does (sin 4) and (foo 1 4) does (cos 4).

现在我们可能有:

(foo (+ 2 1) 4)

这并没有给出想要的结果.

This does not give the desired result.

然后可能希望通过评估变量来修复宏 FOO:

One then may want to repair the macro FOO by EVALuating the variable:

(defmacro foo (a b)
  (list (if (eql (eval a) 3) 'sin 'cos) b))

(foo (+ 2 1) 4)

但是这仍然不起作用:

(defun bar (a b)
  (foo a b))

变量的值在编译时是未知的.

The value of the variable is just not known at compile time.

避免EVAL的一般重要原因:它通常用于丑陋的黑客攻击.

A general important reason to avoid EVAL: it is often used for ugly hacks.

这篇关于为什么 eval 是邪恶的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆