人们不应该使用的原因有很多EVAL
。
初学者的主要原因是:您不需要它。
示例(假设Common Lisp):
用不同的运算符评估表达式:
(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
show表示对评估人员缺乏了解。
宏也是同样的问题。初学者通常会在其中编写函数的地方编写宏-不了解宏的真正用途并且不了解函数已经完成了工作。
它通常是该工作使用的错误工具,EVAL
并且通常表明初学者不了解通常的Lisp评估规则。
如果您认为需要EVAL
,请检查是否有类似的东西FUNCALL
,REDUCE
或者APPLY
可以代替使用。
FUNCALL
-使用参数调用函数: (funcall '+ 1 2 3)
REDUCE
-在值列表上调用函数并合并结果: (reduce '+ '(1 2 3))
APPLY
-调用以列表为参数的函数:(apply '+ '(1 2 3))
。
问:我真的需要评估吗,还是编译器/评估器已经是我真正想要的?
避免EVAL
使用高级用户的主要原因:
用简化的示例解释最后一点:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
因此,我可能想编写一个基于第一个参数使用SIN
或的宏COS
。
(foo 3 4)
做(sin 4)
和(foo 1 4)
做(cos 4)
。
现在我们可能有:
(foo (+ 2 1) 4)
这不会产生期望的结果。
然后可能要FOO
通过EVALuating变量来修复宏:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
但这仍然不起作用:
(defun bar (a b)
(foo a b))
只是在编译时不知道变量的值。
要避免的一般重要原因EVAL
:它通常用于丑陋的骇客。