Ada beberapa alasan mengapa seseorang tidak boleh menggunakannya EVAL
.
Alasan utama untuk pemula adalah: Anda tidak membutuhkannya.
Contoh (dengan asumsi Common Lisp):
EVALuasikan ekspresi dengan operator yang berbeda:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
Itu lebih baik ditulis sebagai:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Ada banyak contoh di mana pemula belajar Lisp berpikir mereka butuhkan EVAL
, tetapi mereka tidak membutuhkannya - karena ekspresi dievaluasi dan orang juga dapat mengevaluasi bagian fungsi. Sebagian besar waktu penggunaan EVAL
menunjukkan kurangnya pemahaman evaluator.
Ini adalah masalah yang sama dengan makro. Seringkali pemula menulis makro, di mana mereka harus menulis fungsi - tidak memahami apa sebenarnya makro dan tidak memahami bahwa fungsi sudah melakukan pekerjaan.
Ini sering merupakan alat yang salah untuk pekerjaan yang harus digunakan EVAL
dan sering menunjukkan bahwa pemula tidak memahami aturan evaluasi Lisp yang biasa.
Jika Anda merasa perlu EVAL
, periksa apakah ada yang suka FUNCALL
, REDUCE
atau APPLY
bisa digunakan.
FUNCALL
- panggil fungsi dengan argumen: (funcall '+ 1 2 3)
REDUCE
- panggil fungsi pada daftar nilai dan gabungkan hasilnya: (reduce '+ '(1 2 3))
APPLY
- memanggil fungsi dengan daftar sebagai argumen: (apply '+ '(1 2 3))
.
T: apakah saya benar-benar membutuhkan eval atau apakah kompiler / evaluator sudah seperti yang saya inginkan?
Alasan utama untuk menghindari EVAL
pengguna yang sedikit lebih maju:
Anda ingin memastikan bahwa kode Anda dikompilasi, karena kompiler dapat memeriksa kode untuk banyak masalah dan menghasilkan kode lebih cepat, kadang-kadang JAUH JAUH JAUH (itu faktor 1000 ;-)) kode lebih cepat
kode yang dibangun dan perlu dievaluasi tidak dapat dikompilasi sedini mungkin.
eval input pengguna sewenang-wenang membuka masalah keamanan
beberapa penggunaan evaluasi EVAL
dapat terjadi pada waktu yang salah dan menimbulkan masalah pembangunan
Untuk menjelaskan poin terakhir dengan contoh sederhana:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Jadi, saya mungkin ingin menulis makro yang didasarkan pada parameter pertama menggunakan salah satu SIN
atau COS
.
(foo 3 4)
lakukan (sin 4)
dan (foo 1 4)
lakukan (cos 4)
.
Sekarang kita mungkin memiliki:
(foo (+ 2 1) 4)
Ini tidak memberikan hasil yang diinginkan.
Seseorang kemudian mungkin ingin memperbaiki makro FOO
dengan MENGEVALUASI variabel:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Tapi ini masih tidak berhasil:
(defun bar (a b)
(foo a b))
Nilai variabel tidak diketahui pada waktu kompilasi.
Alasan umum yang penting untuk dihindari EVAL
: sering digunakan untuk peretasan yang buruk.