Є кілька причин, чому не слід користуватися EVAL.
Основна причина для початківців: вам це не потрібно.
Приклад (якщо припустити звичайний Lisp):
ОЦІНЮЙТЕ вираз з різними операторами:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
Це краще писати як:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Є чимало прикладів, коли початківці, які навчаються Ліспу, думають, що їм це потрібно EVAL, але їм це не потрібно - оскільки вирази оцінюються і можна також оцінити функціональну частину. Більшість випадків використання EVALпоказує недостатнє розуміння оцінювача.
Така ж проблема і з макросами. Часто початківці пишуть макроси, куди вони повинні писати функції - не розуміючи, для чого насправді є макроси, і не розуміючи, що функція вже виконує цю роботу.
Часто це неправильний інструмент для роботи, який використовується, EVALі часто вказує на те, що новачок не розуміє звичних правил оцінювання Lisp.
Якщо ви вважаєте, що вам потрібно EVAL, то перевірте FUNCALL, REDUCEчи APPLYможе щось замість цього використовуватись.
FUNCALL - виклик функції з аргументами: (funcall '+ 1 2 3)
REDUCE - викликати функцію у списку значень та об'єднати результати: (reduce '+ '(1 2 3))
APPLY- виклик функції зі списком в якості аргументів: (apply '+ '(1 2 3)).
Питання: чи мені справді потрібен eval чи компілятор / оцінювач вже те, що мені дійсно хочеться?
Основні причини, яких слід уникати EVALдля трохи просунутіших користувачів:
ви хочете переконатися, що ваш код скомпільований, тому що компілятор може перевірити код на наявність багатьох проблем і генерувати швидший код, іноді МНОГО СТОЛЬКО (це фактор 1000 ;-)) швидший код
Код, який побудований і який повинен бути оцінений, не може бути скомпільований якомога раніше.
eval довільного введення користувача відкриває проблеми із безпекою
деяке використання оцінювання з 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: її часто використовують для некрасивих хак.