Defun dentro let con associazione lessicale avverte di compilazione byte "la funzione non è nota per essere definita"


13

Voglio ottenere l'effetto di una variabile statica usando defuninside of letcon associazione lessicale per creare una chiusura. Tuttavia, durante la compilazione di byte del file, viene visualizzato un avviso. Sto facendo qualcosa di sbagliato o, in caso contrario, c'è un modo per sopprimere questo avviso?

Ho creato un 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))

Il codice funziona come previsto: la funzione increase-countstampa "Count is: n" dove n aumenta ogni volta che viene chiamato. Tuttavia, durante la compilazione di byte di questo file, ricevo il seguente avviso:

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

Mi sembra che increase-countdebba sempre essere definito prima che venga chiamato alla fine del let-block. Non è così?


defunnon fa quello che pensi che faccia, crea sempre una definizione di alto livello. Dopotutto Elisp non è Scheme ...
wasamasa,

2
Sono consapevole che crea una definizione di livello superiore; è quello che voglio. Voglio solo che la definizione di massimo livello sia una chiusura. Sembra funzionare nel modo desiderato, ad eccezione di questo avviso di compilazione di byte.
Will Kunkel,

Risposte:


7

Il modo in cui il compilatore di byte decide se una funzione verrà definita o meno è molto "ingenuo" e viene ingannato anche nel caso "ovvio". Ma puoi scriverlo in un modo che consenta al compilatore di capire cosa succede:

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

Certo, sarebbe ancora meglio migliorare la logica del compilatore di byte: patch benvenute per questo.


5

Per sopprimere l'avviso del compilatore di byte, prova ad aggiungere questo prima del codice, iniziando dalla colonna 0 (all'estrema sinistra):

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

C-h f declare-function ti dice:

declare-functionè una macro Lisp in subr.el.

(declare-function FN FILE &optional ARGLIST FILEONLY)

Indica al compilatore di byte che la funzione FNè definita, in FILE. L' FILEargomento non viene utilizzato dal compilatore di byte, ma dal check-declarepacchetto, che verifica che FILE contenga una definizione per FN.

FILEpuò essere un file Lisp (nel qual caso l' ".el" estensione è facoltativa) o un file C. I file C vengono espansi rispetto alla "src/"directory Emacs . I file Lisp vengono cercati per l'utilizzo locate-librarye, in caso contrario, vengono espansi in relazione alla posizione del file contenente la dichiarazione. A FILEcon un "ext:"prefisso è un file esterno. check-declarecontrollerà tali file se vengono trovati e li salterà senza errori se non lo sono.

Facoltativo ARGLISTspecifica FNgli argomenti, oppure è tdi non specificare FNgli argomenti. Un ARGLISTvalore predefinito omesso tè nil: no : a nil ARGLISTspecifica un elenco di argomenti vuoto e un esplicito t ARGLISTè un segnaposto che consente di fornire un argomento successivo.

Facoltativi FILEONLYnon nilsignifica che check-declarecontrollerà soltanto che FILEesiste, non che definisce FN. Questo è inteso per definizioni di funzioni che check-declarenon riconoscono, ad es defstruct.

Si noti che ai fini di check-declare, questa affermazione deve essere il primo non-spazio bianco su una riga.

Per ulteriori informazioni, consultare il nodo Informazioni (elisp)Declaring Functions.


È necessario un FILEONLYargomento non nullo per il caso in esame? A proposito, avrei dato la stessa risposta ;-).
Tobias,

@Tobias: FILEONLYnon sembrava essere necessario qui, per me. Il che sembrerebbe indicare che check-declarericonosce fe gsconfigge.
Estratto il

@Drew, penso che l'ultimo commento fe gabbia senso solo nel contesto di emacs.stackexchange.com/q/39439 ?
phils,

@phils: Sì, intendevo dire questo: FILEONLYnon sembrava essere necessario qui, per me. Il che sembrerebbe indicare che check-declarericonosce il increase-countdefun. ;-)
Drew

3

Credo che collocare la definizione in questione eval-and-compilepossa raggiungere superficialmente lo stesso risultato della risposta corretta di Stefan :

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

Tuttavia, conosco a malapena le sottigliezze dell'uso eval-and-compilee, inoltre, non mi aspetto che questo approccio sia in alcun modo superiore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.