有哪些方法可以避免在计划中使用eval?是否存在绝对需要评估的情况?
答案 0 :(得分:7)
有些情况下eval
是必需的,但它们总是涉及高级程序,这些程序可以动态加载某些代码(例如,Web服务器中的servlet)。至于“规避”使用它的方法 - 这取决于你试图解决的实际问题,除了... eval
之外,没有任何神奇的解决方案来避免eval
。
(顺便说一句,我的猜测是PAIP是很久以前写的,在eval
被添加到计划报告之前。)
答案 1 :(得分:4)
他错了。当然,Scheme中有eval
。
答案 2 :(得分:3)
在极少数情况下你需要eval
。首先想到的情况是,您将使用程序构建程序然后执行它。这主要发生在遗传算法上。在这种情况下,您构建了许多您需要执行的随机程序。将eval
与代码作为数据相结合使lisp成为进行遗传算法的最简单的编程语言。
拥有这些属性需要付出巨大的代价(在程序的速度和大小方面),因为你将删除所有可能对代码进行编译时优化的可能性,你必须保留完整的解释器结果二进制。
因此,当可以避免时,使用eval
被认为设计不佳。
答案 3 :(得分:3)
至少对于最新版本的Scheme标准(R5RS及更高版本),Scheme没有eval
的声明是不准确的。通常,你想要的是一个宏,它将在编译时生成代码。
确实应该避免使用eval
。首先,我从未见过如何表现出令人满意的定义,例如:
也就是说,我使用了一个Scheme应用程序,该应用程序使用eval
在运行时动态生成代码,以防在编译时无法知道计算结构。出于性能原因,目的是让Scheme系统在运行时编译代码 - 并且困难在于没有标准方法来告诉Scheme系统“编译此代码。”
不言而喻,eval
可能是一个巨大的安全风险。你永远不应该eval
任何与用户输入没有巨大隔离墙的东西。基本上,如果你想安全地使用eval
,你应该在编译器类系统的代码生成阶段的上下文中,在你解析了一些输入之后(使用全面定义的语法!)
答案 4 :(得分:1)
首先,PAIP是为Common Lisp而不是Scheme编写的,所以我不知道他会说同样的事情。 CL宏与eval
的功能大致相同,尽管在编译时而不是运行时,您还可以执行其他操作。如果你给我看一个在Common Lisp中使用eval
的例子,我可以试着想出其他做同样事情的方法。
我不是Scheme程序员。作为Common Lisp程序员,我只能从Norvig的角度讲。我不认为他在谈论Scheme,我不知道他是否特别熟悉或了解Scheme。
其次,Norvig说“你可能做错了”,而不是“你做错了”。这意味着,尽管他知道,有时eval
是正确的事情。在像C这样的语言中,我会对goto
说同样的话,虽然它们在某些受限制的情况下非常有用,但大多数goto
使用的是那些不知道更好的人。
答案 5 :(得分:0)
我在脚本环境中看到的'eval'的一个用途是使用运行时值来参数化一些代码。例如,在psuedo-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,但参数化代码和代码组合可以用第一类函数生成。
答案 6 :(得分:-1)
你可以在方案中编写一个方案解释器。这当然是可能的,但这是不切实际的。
当然,这是一个普遍的答案,因为我没有使用过计划,但它可能对你有帮助。 :)