Es gibt mehrere Gründe, warum man nicht verwenden sollte EVAL
.
Der Hauptgrund für Anfänger ist: Sie brauchen es nicht.
Beispiel (unter der Annahme von Common Lisp):
BEWERTEN Sie einen Ausdruck mit verschiedenen Operatoren:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
Das ist besser geschrieben als:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Es gibt viele Beispiele, bei denen Anfänger, die Lisp lernen, glauben EVAL
, dass sie es brauchen , aber sie brauchen es nicht - da Ausdrücke ausgewertet werden und man auch den Funktionsteil bewerten kann. Meistens EVAL
zeigt die Verwendung von ein Unverständnis des Bewerters.
Es ist das gleiche Problem mit Makros. Oft schreiben Anfänger Makros, in die sie Funktionen schreiben sollen - ohne zu verstehen, wofür Makros wirklich sind, und ohne zu verstehen, dass eine Funktion bereits die Aufgabe erfüllt.
Es ist oft das falsche Werkzeug für den Job EVAL
und zeigt oft an, dass der Anfänger die üblichen Lisp-Bewertungsregeln nicht versteht.
Wenn Sie denken , Sie brauchen EVAL
, dann prüfen , ob so etwas wie FUNCALL
, REDUCE
oder APPLY
könnte stattdessen verwendet werden.
FUNCALL
- eine Funktion mit Argumenten aufrufen: (funcall '+ 1 2 3)
REDUCE
- Rufen Sie eine Funktion in einer Werteliste auf und kombinieren Sie die Ergebnisse: (reduce '+ '(1 2 3))
APPLY
- Rufen Sie eine Funktion mit einer Liste als Argument auf : (apply '+ '(1 2 3))
.
F: Brauche ich wirklich eine Bewertung oder hat der Compiler / Evaluator bereits das, was ich wirklich will?
Die Hauptgründe EVAL
für etwas fortgeschrittenere Benutzer zu vermeiden :
Sie möchten sicherstellen, dass Ihr Code kompiliert wird, da der Compiler Code auf viele Probleme überprüfen kann und schnelleren Code generiert, manchmal VIEL VIEL VIEL (das ist Faktor 1000 ;-)) schnellerer Code
Code, der erstellt wurde und ausgewertet werden muss, kann nicht so früh wie möglich kompiliert werden.
Die Auswertung willkürlicher Benutzereingaben führt zu Sicherheitsproblemen
Einige Anwendungen der Evaluierung mit EVAL
können zur falschen Zeit erfolgen und Build-Probleme verursachen
Um den letzten Punkt mit einem vereinfachten Beispiel zu erklären:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Daher möchte ich möglicherweise ein Makro schreiben, das basierend auf dem ersten Parameter entweder SIN
oder verwendet COS
.
(foo 3 4)
tut (sin 4)
und (foo 1 4)
tut (cos 4)
.
Jetzt haben wir vielleicht:
(foo (+ 2 1) 4)
Dies ergibt nicht das gewünschte Ergebnis.
Man kann dann das Makro reparieren, FOO
indem man die Variable bewertet:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Aber dann funktioniert das immer noch nicht:
(defun bar (a b)
(foo a b))
Der Wert der Variablen ist zur Kompilierungszeit einfach nicht bekannt.
Ein allgemeiner wichtiger Grund zu vermeiden EVAL
: Es wird oft für hässliche Hacks verwendet.