Ci sono diversi motivi per cui non si dovrebbe usare EVAL
.
Il motivo principale per i principianti è: non ne hai bisogno.
Esempio (presupponendo Common Lisp):
VALUTARE un'espressione con diversi operatori:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
È meglio scritto come:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Ci sono molti esempi in cui i principianti che imparano Lisp pensano di aver bisogno EVAL
, ma non ne hanno bisogno, poiché le espressioni vengono valutate e si può anche valutare la parte della funzione. Il più delle volte l'uso di EVAL
mostra una mancanza di comprensione del valutatore.
È lo stesso problema con le macro. Spesso i principianti scrivono macro, dove dovrebbero scrivere funzioni - non capire a cosa servono veramente le macro e non capire che una funzione fa già il lavoro.
Spesso è lo strumento sbagliato da utilizzare per il lavoro EVAL
e spesso indica che il principiante non capisce le solite regole di valutazione Lisp.
Se pensi di aver bisogno EVAL
, quindi verificare se qualcosa di simile FUNCALL
, REDUCE
o APPLY
potrebbe essere usato al posto.
FUNCALL
- chiama una funzione con argomenti: (funcall '+ 1 2 3)
REDUCE
- chiama una funzione su un elenco di valori e combina i risultati: (reduce '+ '(1 2 3))
APPLY
- chiamare una funzione con una lista come argomenti: (apply '+ '(1 2 3))
.
D: Ho davvero bisogno di eval o il compilatore / valutatore fa già quello che voglio davvero?
I motivi principali da evitare EVAL
per utenti leggermente più avanzati:
vuoi assicurarti che il tuo codice sia compilato, perché il compilatore può controllare il codice per molti problemi e genera codice più veloce, a volte MOLTO MOLTO MOLTO (che è il fattore 1000 ;-)) codice più veloce
il codice costruito e che deve essere valutato non può essere compilato il prima possibile.
la valutazione di input dell'utente arbitrario apre problemi di sicurezza
un certo uso della valutazione EVAL
può avvenire nel momento sbagliato e creare problemi di costruzione
Per spiegare l'ultimo punto con un esempio semplificato:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Quindi, potrei voler scrivere una macro che in base al primo parametro utilizza SIN
o COS
.
(foo 3 4)
fa (sin 4)
e (foo 1 4)
fa (cos 4)
.
Ora potremmo avere:
(foo (+ 2 1) 4)
Questo non dà il risultato desiderato.
Uno potrebbe quindi voler riparare la macro FOO
EVALuando la variabile:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Ma poi questo non funziona ancora:
(defun bar (a b)
(foo a b))
Il valore della variabile non è noto al momento della compilazione.
Un motivo generale importante da evitare EVAL
: è spesso usato per brutti hack.