Istnieje kilka powodów, dla których nie powinno się ich używać EVAL
.
Głównym powodem dla początkujących jest: nie potrzebujesz tego.
Przykład (zakładając Common Lisp):
OCENA wyrażenia za pomocą różnych operatorów:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
To lepiej napisać jako:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Istnieje wiele przykładów, w których początkujący uczący się Lispa myślą, że potrzebują EVAL
, ale nie potrzebują tego - ponieważ wyrażenia są oceniane i można również ocenić część funkcji. W większości przypadków użycie EVAL
znaku wskazuje na brak zrozumienia ewaluatora.
Ten sam problem dotyczy makr. Często początkujący piszą makra, w których powinni pisać funkcje - nie rozumiejąc, do czego naprawdę służą makra i nie rozumiejąc, że funkcja już wykonuje swoje zadanie.
Często jest to niewłaściwe narzędzie do pracy EVAL
i często wskazuje, że początkujący nie rozumie zwykłych zasad oceny Lisp.
Jeśli uważasz, że potrzebujesz EVAL
, sprawdź FUNCALL
, REDUCE
czy APPLY
zamiast tego można użyć czegoś takiego lub .
FUNCALL
- wywołaj funkcję z argumentami: (funcall '+ 1 2 3)
REDUCE
- wywołaj funkcję na liście wartości i połącz wyniki: (reduce '+ '(1 2 3))
APPLY
- wywołać funkcję z listy jako argumentów: (apply '+ '(1 2 3))
.
P: Czy naprawdę potrzebuję eval, czy też kompilator / oceniający już to, czego naprawdę chcę?
Główne powody, których należy unikać w EVAL
przypadku nieco bardziej zaawansowanych użytkowników:
chcesz mieć pewność, że Twój kod jest skompilowany, ponieważ kompilator może sprawdzić kod pod kątem wielu problemów i generuje szybszy kod, czasami DUŻO DUŻO (to współczynnik 1000 ;-)) szybszy kod
kod, który jest skonstruowany i musi zostać oceniony, nie może zostać skompilowany tak wcześnie, jak to możliwe.
ocena arbitralnych danych wejściowych użytkownika stwarza problemy związane z bezpieczeństwem
niektóre zastosowania ewaluacji EVAL
mogą się wydarzyć w złym czasie i spowodować problemy z kompilacją
Aby wyjaśnić ostatni punkt za pomocą uproszczonego przykładu:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Więc może zechcę napisać makro, które na podstawie pierwszego parametru używa albo SIN
lub COS
.
(foo 3 4)
robi (sin 4)
i (foo 1 4)
robi (cos 4)
.
Teraz możemy mieć:
(foo (+ 2 1) 4)
Nie daje to pożądanego rezultatu.
Wtedy można chcieć naprawić makro FOO
, oceniając zmienną:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Ale to nadal nie działa:
(defun bar (a b)
(foo a b))
Wartość zmiennej po prostu nie jest znana w czasie kompilacji.
Ogólny ważny powód, którego należy unikać EVAL
: jest często używany do brzydkich hacków.