Основна проблема полягає в тому, що семантика прив'язки для невизначених змінних - тобто змінних, не визначених за допомогою defvarдрузів, - змінюється на lexical-binding: Без цього letпов'язує все динамічно, але з lexical-bindingувімкненими невизначеними змінними пов'язані лексично і навіть повністю витікають, якщо не використовуються в поточній лексичній області .
Старий код іноді покладається на це. Щоб уникнути жорстких залежностей від додаткових функцій, він прив'язує динамічні змінні, не вимагаючи відповідної бібліотеки або оголошуючи саму змінну:
(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тепер пов'язаний лексично (а потім оптимізується геть, бо вона не використовується), тому глобальна змінна динамічного 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завершення? Я майже впевнений, що натрапив на помилку, як це раніше. Дефвара відбувалася всерединіlet, аletпізніше відновила змінну до її початкового (недійсного) стану.