Defun inside let mit lexikalischer Bindung gibt die Warnung beim Kompilieren von Bytes aus, dass die Funktion nicht als definiert bekannt ist.

13

Ich möchte den Effekt einer statischen Variablen erhalten, indem ich defuninside of letmit lexikalischer Bindung verwende, um einen Abschluss zu erstellen. Beim Byte-Kompilieren der Datei erhalte ich jedoch eine Warnung. Mache ich etwas falsch oder gibt es eine Möglichkeit, diese Warnung zu unterdrücken?

Ich habe ein MCVE erstellt:

;; -*- 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))

Der Code funktioniert wie erwartet: Die Funktion gibt increase-count"Count is: n" aus, wobei sich n bei jedem Aufruf erhöht. Beim Kompilieren dieser Datei mit Bytes erhalte ich jedoch die folgende Warnung:

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

Es scheint mir, dass increase-countimmer definiert werden sollte, bevor es am Ende des Let-Blocks aufgerufen wird. Ist das nicht der Fall?

Will Kunkel
quelle
defunTut nicht das, was Sie denken, sondern erstellt immer eine Definition auf oberster Ebene. Elisp ist immerhin nicht Schema ...
Wasamasa
2
Mir ist bewusst, dass damit eine Definition auf oberster Ebene erstellt wird. das ist, was ich will. Ich möchte nur, dass diese Definition der obersten Ebene ein Abschluss ist. Es scheint so zu funktionieren, wie ich es möchte, mit Ausnahme dieser Warnung zur Bytekompilierung.
Will Kunkel

Antworten:

7

Die Art und Weise des Byte-Compilers zu entscheiden, ob eine Funktion definiert wird oder nicht, ist sehr "naiv" und wird selbst in Ihrem "offensichtlichen" Fall getäuscht. Sie können es jedoch so schreiben, dass der Compiler versteht, was passiert:

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

Noch besser wäre es natürlich, die Logik des Byte-Compilers zu verbessern: Patches sind dafür willkommen.

Stefan
quelle
5

Um die Warnung des Byte-Compilers zu unterdrücken, fügen Sie diese vor Ihrem Code hinzu, beginnend in Spalte 0 (ganz links):

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

C-h f declare-function sagt Ihnen:

declare-functionist ein Lisp-Makro in subr.el.

(declare-function FN FILE &optional ARGLIST FILEONLY)

Teilen Sie dem Byte-Compiler mit, welche Funktion FNdefiniert ist FILE. Das FILEArgument wird nicht vom Byte-Compiler verwendet, sondern vom check-declarePaket, das prüft, ob FILE eine Definition für enthält FN.

FILEDies kann entweder eine Lisp-Datei (in diesem Fall ist die ".el" Erweiterung optional) oder eine C-Datei sein. C-Dateien werden relativ zum Emacs- "src/"Verzeichnis erweitert. Lisp-Dateien werden nach ihrer Verwendung durchsucht. locate-libraryWenn dies fehlschlägt, werden sie relativ zum Speicherort der Datei, die die Deklaration enthält, erweitert. Ein FILEmit einem "ext:"Präfix ist eine externe Datei. check-declareprüft solche Dateien, wenn sie gefunden werden, und überspringt sie ohne Fehler, wenn sie nicht gefunden werden.

Optional ARGLISTgibt FNdie Argumente an oder gibt tdie FNArgumente nicht an. Ein ausgelassenes Argument hat den ARGLISTStandardwert t, nicht nil: a nil ARGLISTgibt eine leere Argumentliste an, und ein explizites Argument t ARGLISTist ein Platzhalter, mit dem ein späteres Argument angegeben werden kann.

Optional bedeutet FILEONLYnicht nil, dass check-declarenur das überprüft wird, was FILEexistiert, nicht das, was definiert wird FN. Dies ist für Funktionsdefinitionen gedacht check-declare, die z defstruct.

Beachten Sie, dass check-declarediese Anweisung für die Zwecke von das erste Nicht-Leerzeichen in einer Zeile sein muss.

Weitere Informationen finden Sie unter Infoknoten (elisp)Declaring Functions.

Drew
quelle
Ist FILEONLYfür den vorliegenden Fall ein Nicht-Null- Argument erforderlich? Übrigens hätte ich die gleiche Antwort gegeben ;-).
Tobias
@Tobias: FILEONLYschien hier nicht nötig zu sein, für mich. Was darauf hinzudeuten scheint, dass das check-declareerkennt fund gzunichte macht.
Drew
@Drew, ich denke, dass letzter Kommentar zu fund gnur im Zusammenhang mit emacs.stackexchange.com/q/39439 Sinn macht ?
Phils
@phils: Ja, ich wollte das sagen: FILEONLYschien hier für mich nicht nötig zu sein. Was anscheinend darauf hindeutet, dass check-declareder increase-countVerstorbene erkennt . ;-)
Drew
3

Ich glaube, die Definition in Frage zu stellen, eval-and-compilewürde auch oberflächlich das gleiche Ergebnis erzielen wie in Stefans richtiger Antwort :

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

Ich bin jedoch kaum mit den Feinheiten der Verwendung vertraut eval-and-compileund erwarte außerdem nicht, dass dieser Ansatz in irgendeiner Weise überlegen ist.

Basilikum
quelle