Основной недостаток заключается в том, что семантика связывания для неопределенных переменных, т. Е. Переменных, не определенных с 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как динамическую переменную, но не влияет на строку документации, load-history(и, следовательно, на find-variableдрузей) или что-либо еще, кроме характера привязки переменной.
cook-eggs-enabledстанет несвязанным послеletзавершения? Я почти уверен, что сталкивался с такой ошибкой раньше. Defvar происходил внутриlet, иletпозже восстановил переменную в ее начальное (пустое) состояние.