Hay varias razones por las cuales uno no debe usar EVAL
.
La razón principal para los principiantes es: no lo necesitas.
Ejemplo (suponiendo Common Lisp):
EVALUAR una expresión con diferentes operadores:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
Eso está mejor escrito como:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Hay muchos ejemplos en los que los principiantes que aprenden Lisp piensan que necesitan EVAL
, pero no lo necesitan, ya que las expresiones se evalúan y también se puede evaluar la parte de la función. La mayoría de las veces el uso de EVAL
muestra una falta de comprensión del evaluador.
Es el mismo problema con las macros. A menudo, los principiantes escriben macros, donde deben escribir funciones, sin entender para qué son realmente las macros y sin entender que una función ya hace el trabajo.
A menudo es la herramienta incorrecta para el trabajo EVAL
y a menudo indica que el principiante no comprende las reglas habituales de evaluación de Lisp.
Si cree que lo necesita EVAL
, verifique si algo como FUNCALL
, REDUCE
o APPLY
podría usarse en su lugar.
FUNCALL
- llamar a una función con argumentos: (funcall '+ 1 2 3)
REDUCE
- llame a una función en una lista de valores y combine los resultados: (reduce '+ '(1 2 3))
APPLY
- llamar a una función con una lista como los argumentos: (apply '+ '(1 2 3))
.
P: ¿realmente necesito evaluar o el compilador / evaluador ya es lo que realmente quiero?
Las principales razones a evitar EVAL
para usuarios un poco más avanzados:
desea asegurarse de que su código esté compilado, porque el compilador puede verificar el código en busca de muchos problemas y genera código más rápido, a veces MUCHO MUCHO (factor 1000 ;-)) código más rápido
el código que se construye y necesita ser evaluado no se puede compilar lo antes posible.
la evaluación de la entrada arbitraria del usuario abre problemas de seguridad
cierto uso de la evaluación EVAL
puede ocurrir en el momento equivocado y crear problemas de compilación
Para explicar el último punto con un ejemplo simplificado:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Por lo tanto, es posible que desee escribir una macro que, según el primer parámetro, use SIN
o COS
.
(foo 3 4)
hace (sin 4)
y (foo 1 4)
hace (cos 4)
.
Ahora podemos tener:
(foo (+ 2 1) 4)
Esto no da el resultado deseado.
Entonces, uno puede querer reparar la macro FOO
EVALUANDO la variable:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Pero esto todavía no funciona:
(defun bar (a b)
(foo a b))
El valor de la variable simplemente no se conoce en tiempo de compilación.
Una razón general importante para evitar EVAL
: a menudo se usa para hacks feos.