อันตรายที่สำคัญคือความหมายผูกพันที่ไม่ได้กำหนดตัวแปรตัวแปรคือไม่กำหนดด้วยdefvarและเพื่อน ๆ เปลี่ยนกับlexical-binding: โดยไม่ได้letผูกทุกอย่างแบบไดนามิก แต่มีlexical-bindingตัวแปรที่ไม่ได้กำหนดเปิดใช้งานจะผูกพันlexicallyและ elided แม้สมบูรณ์หากไม่ได้ใช้ในขอบเขตของคำศัพท์ในปัจจุบัน .
รหัสเก่าบางครั้งอาศัยสิ่งนี้ เพื่อหลีกเลี่ยงการขึ้นต่อกันอย่างหนักสำหรับฟีเจอร์เสริมมันจะผูกตัวแปรแบบไดนามิกโดยไม่ต้องมีไลบรารี่ที่เกี่ยวข้องหรือประกาศตัวแปรเอง:
(let ((cook-eggs-enabled t))
(cook-my-meal))
หากคุณลักษณะการทำอาหารเป็นตัวเลือกเราไม่ต้องการบังคับให้มีการพึ่งพาที่ไม่จำเป็นกับผู้ใช้ดังนั้นเราจึงไม่ใช้(require 'cook)และพึ่งพาcook-my-mealฟังก์ชั่นการ โหลดอัตโนมัติ
เป็นที่ชัดเจนสำหรับผู้อ่านของมนุษย์ที่cook-eggs-enabledไม่ได้เป็นตัวแปรในตัวเครื่อง แต่ยังคงอ้างถึงตัวแปรแบบไดนามิกทั่วโลกจากcookไลบรารีที่นี่ หากไม่มีlexical-bindingรหัสนี้จะทำงานตามที่ต้องการ: cook-eggs-enabledถูกผูกไว้แบบไดนามิกไม่ว่าจะถูกกำหนดไว้หรือไม่ก็ตาม
lexical-bindingอย่างไรก็ตามด้วยการแบ่งมัน: cook-eggs-enabledถูกผูกไว้กับlexically (และปรับให้เหมาะสมเนื่องจากไม่ได้ใช้) ดังนั้นตัวแปรแบบไดนามิกทั่วโลกcook-eggs-enabledจึงไม่เคยสัมผัสเลยและยัง ถูกเรียกnilตามเวลาcook-my-mealดังนั้นเราแปลกใจที่ไม่มีไข่ ในมื้ออาหารของเรา
โชคดีที่ปัญหาเหล่านี้เป็นเรื่องง่ายที่จะสังเกตเห็น : คอมไพเลอร์ไบต์ตามธรรมชาติเตือนเกี่ยวกับคำศัพท์ที่ไม่ได้ใช้ที่นี่
การแก้ไขง่ายๆคือ: ทั้งเพิ่ม(require 'cook)(สำหรับคุณสมบัติที่ไม่ได้อยู่แล้วไม่จำเป็นจริงๆ) หรือเพื่อหลีกเลี่ยงยากที่อ้างอิง-ประกาศตัวแปรเป็นตัวแปรแบบไดนามิกในรหัสของคุณเอง มีdefvarรูปแบบพิเศษสำหรับสิ่งนี้:
(defvar cook-eggs-enabled)
สิ่งนี้นิยามcook-eggs-enabledว่าเป็นตัวแปรแบบไดนามิก แต่ไม่มีผลกับ docstring, load-history(และfind-variableและเพื่อน ๆ ) หรือสิ่งอื่นใดยกเว้นลักษณะการผูกของตัวแปร
cook-eggs-enabledจะไม่ถูกดึงออกเมื่อทำletเสร็จหรือไม่ ฉันค่อนข้างแน่ใจว่าฉันพบข้อผิดพลาดเช่นนี้มาก่อน defvar เกิดขึ้นภายในletและletหลังจากนั้นคืนค่าตัวแปรให้เป็นสถานะเริ่มต้น (โมฆะ)