EVAL
มีเหตุผลหลายประการที่หนึ่งไม่ควรใช้
เหตุผลหลักสำหรับผู้เริ่มต้นคือคุณไม่ต้องการมัน
ตัวอย่าง (สมมติว่า Common LISP):
หาค่านิพจน์ด้วยตัวดำเนินการอื่น:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
นั่นเขียนได้ดีกว่า:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
มีตัวอย่างมากมายที่ผู้เริ่มต้นเรียนรู้ Lisp คิดว่าพวกเขาต้องการEVAL
แต่พวกเขาไม่ต้องการ - เนื่องจากมีการประเมินนิพจน์และสามารถประเมินส่วนของฟังก์ชันได้เช่นกัน เวลาส่วนใหญ่ที่ใช้EVAL
แสดงให้เห็นถึงการขาดความเข้าใจของผู้ประเมิน
มันเป็นปัญหาเดียวกันกับมาโคร บ่อยครั้งที่ผู้เริ่มต้นเขียนแมโครซึ่งพวกเขาควรจะเขียนฟังก์ชั่น - ไม่เข้าใจว่ามาโครตัวใดมีไว้เพื่ออะไรจริงๆและไม่เข้าใจว่าฟังก์ชั่นทำงานอยู่แล้ว
บ่อยครั้งเป็นเครื่องมือที่ไม่ถูกต้องสำหรับงานที่ใช้EVAL
และมักจะระบุว่าผู้เริ่มต้นไม่เข้าใจกฎการประเมินผลเสียงกระเพื่อมตามปกติ
หากคุณคิดว่าคุณต้องEVAL
แล้วตรวจสอบว่าสิ่งที่ชอบFUNCALL
, REDUCE
หรือAPPLY
อาจจะนำมาใช้แทน
FUNCALL
- เรียกใช้ฟังก์ชันที่มีอาร์กิวเมนต์: (funcall '+ 1 2 3)
REDUCE
- เรียกใช้ฟังก์ชันในรายการค่าและรวมผลลัพธ์: (reduce '+ '(1 2 3))
APPLY
- (apply '+ '(1 2 3))
เรียกใช้ฟังก์ชันที่มีรายชื่อเป็นข้อโต้แย้งนี้:
ถาม: ฉันต้องการ eval จริง ๆ หรือคอมไพเลอร์ / ผู้ประเมินแล้วสิ่งที่ฉันต้องการจริงๆ
เหตุผลหลักที่ควรหลีกเลี่ยงEVAL
สำหรับผู้ใช้ขั้นสูงเล็กน้อย:
คุณต้องการตรวจสอบให้แน่ใจว่าโค้ดของคุณถูกคอมไพล์เพราะคอมไพเลอร์สามารถตรวจสอบรหัสสำหรับปัญหาต่าง ๆ และสร้างรหัสได้เร็วขึ้นบางครั้งจำนวนมากมาก (นั่นคือตัวคูณ 1,000 ;-))
รหัสที่สร้างขึ้นและต้องได้รับการประเมินไม่สามารถรวบรวมได้เร็วที่สุด
การป้อนข้อมูลผู้ใช้โดยพลการจะทำให้เกิดปัญหาด้านความปลอดภัยขึ้น
การใช้การประเมินผลบางอย่างกับ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
โดยการประเมินตัวแปร:
(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
:มักใช้เพื่อการแฮ็กที่น่าเกลียด