可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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.)
回答2:
He's wrong. Of course there is eval
in Scheme.
回答3:
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.
回答4:
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:
- What environment expressions should be evaluated in when no environment is passed?
- 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!).
回答5:
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.
回答6:
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.
回答7:
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. :)