Запустіть всередині нехай з лексичним зв'язуванням дає попередження про компіляцію байтів "функція невідомо визначена"


13

Я хочу отримати ефект статичної змінної, використовуючи defunвнутрішню частину letз лексичним зв'язуванням для створення закриття. Однак при байтовому компілюванні файлу я отримую попередження. Я роблю щось не так, чи ні, чи є спосіб придушити це попередження?

Я створив MCVE:

;; -*- lexical-binding: t -*-

(let ((count 0))
  (defun increase-count ()
    (interactive)
    (setq count (1+ count))
    (message "Count is: %d" count))

  ;; The warning happens here.
  (increase-count))

Код працює як очікується: функція increase-countвиводить "Count is: n", де n збільшується щоразу, коли він викликається. Однак при байтовому компілюванні цього файлу я отримую таке попередження:

In end of data:
mcve.el:11:1:Warning: the function ‘increase-count’ is not known to be
    defined.

Мені здається, що increase-countслід завжди визначатись до того, як вона буде викликана в кінці пускового блоку. Це не так?


defunне робить те, що ви думаєте, що робить, воно завжди створює визначення верхнього рівня. Зрештою, Елісп - це не схема ...
wasamasa

2
Я знаю, що це створює визначення верхнього рівня; це те, що я хочу. Я просто хочу, щоб визначення верхнього рівня було закриттям. Здається, працює так, як я хочу, за винятком цього попередження про компіляцію байтів.
Буде Кункель

Відповіді:


7

Спосіб компілятора байтів вирішити, чи буде визначена функція чи ні, дуже "наївний" і обдурить навіть у вашому "очевидному" випадку. Але ви можете написати це таким чином, що дозволяє компілятору зрозуміти, що відбувається:

(defalias 'increase-count
  (let ((count 0))
    (lambda ()
      (interactive)
      (setq count (1+ count))
      (message "Count is: %d" count))))

Звичайно, ще краще було б вдосконалити логіку компілятора байт: для цього патчі вітаються.


5

Щоб придушити попередження компілятора байтів, спробуйте додати це до свого коду, починаючи зі стовпця 0 (крайній лівий):

(declare-function increase-count "your-file-name.el")

C-h f declare-function каже вам:

declare-functionє макросом Lisp в subr.el.

(declare-function FN FILE &optional ARGLIST FILEONLY)

Скажіть байтовому компілятору, що функція FNвизначена в FILE. FILEАргумент не використовується байт-компілятором, але в check-declareпакеті, який перевіряє , що файл містить визначення FN.

FILEможе бути або файлом Lisp (у такому випадку ".el" розширення необов’язково), або файлом C. Файли C розгорнуті відносно "src/"каталогу Emacs . Файли Lisp шукають за допомогою locate-library, а якщо це не вдається, вони розширюються відносно місця розташування файлу, що містить декларацію. А FILEз "ext:"префіксом - це зовнішній файл. check-declareперевірятиме такі файли, якщо вони знайдені, і пропускає їх без помилок, якщо їх немає.

Необов'язково ARGLISTвказує FNаргументи, або tне вказувати FNаргументи. Пропущений ARGLISTза замовчуванням до t, не nil: a nil ARGLISTвказує порожній список аргументів, а явний t ARGLIST- заповнювач, який дозволяє подавати пізніший аргумент.

Необов’язковий FILEONLYне nilозначає, що check-declareперевірятиме лише те, що FILEіснує, а не те, що він визначає FN. Це призначено для визначення функцій , які check-declareне розпізнає, наприклад, defstruct.

Зауважте, що для цілей check-declareцього твердження має бути першим пробілом у рядку.

Для отримання додаткової інформації див. Інформаційний вузол (elisp)Declaring Functions.


Чи потрібний FILEONLYаргумент, що не відповідає нулю, для цієї справи? До речі, я би дав таку ж відповідь ;-).
Тобіас

@Tobias: FILEONLYмені, здається, тут не потрібно. Що, здавалося б, вказує на те, що check-declareрозпізнає fі gзнищує.
Дрю

@Drew, я думаю, що останній коментар про fі gмає сенс лише в контексті emacs.stackexchange.com/q/39439 ?
філс

@phils: Так, я мав намір сказати це: FILEONLYмені, здається, тут не потрібно. Що, здавалося б, вказує на те, що check-declareвизнає increase-countрозвінчання. ;-)
Дрю

3

Я вважаю, що розміщення цього питання eval-and-compileтакож поверхово досягне того ж результату, що і у правильній відповіді Стефана :

(eval-and-compile
  (let ((count 0))
    (defun increase-count ()
      (interactive)
      (setq count (1+ count))
      (message "Count is: %d" count))))

Я, однак, ледве знайомий з тонкощами використання, eval-and-compileі, крім того, не сподіваюся, що цей підхід в будь-якому разі є вищим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.