Основна проблема полягає в тому, що семантика прив'язки для невизначених змінних - тобто змінних, не визначених за допомогою 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
пізніше відновила змінну до її початкового (недійсного) стану.