'Der Wert des Symbols als Variable ist ungültig' im Rückruf vom URL-Abruf

8

Wenn ich Folgendes ausführe, erhalte ich eine Fehlermeldung:

(defun caller (func)
  (url-retrieve "http://m0smith.freeshell.org/"
   (lambda (status) (funcall func))))


(caller (lambda() (message "called")))

Ergebnis:

error in process filter: Symbol's value as variable is void: func

Was ist der beste Weg, um dieses Problem zu lösen? Grundsätzlich muss ich einen Rückruf von einem anderen Ort annehmen, ihn in ein anderes Lambda einwickeln und diesen als Rückruf zum Abrufen von URLs verwenden.

Wenn ich den Anrufer auf wechsle

(defun caller (func)
  (url-retrieve "http://m0smith.freeshell.org/"
   `(lambda (status) (funcall ,func))))

Es klappt. Ich kann dies jedoch nicht tun, da die Funktion per Flycheck übergeben wird und die Makroerweiterung dies unterbricht. Um den vollständigen Kontext meiner Arbeit zu sehen: https://gist.github.com/m0smith/b5961fda6afd71e82983

M Smith
quelle
Welche Makroerweiterung? Ihr letzter Absatz ist unklar. Veröffentlichen Sie hier eine vollständige Erklärung des Problems. Die Verwendung von Backquote mit Komma ist die Lösung (eine Lösung). Eine andere Möglichkeit besteht darin lexical-let, eine Variable zu verwenden oder einzustellen lexical-binding. Bitte machen Sie deutlich, wo das Problem mit dem nicht angezeigten "Makro" liegt.
Drew
Ich nahm an, dass die `und, Makro erweitert wurden. Wie auch immer diese Form dann heißt. Ich möchte in EMACS 23 arbeiten. Gibt es eine lexikalische Funktion?
M Smith
Wenn es keine Verwendung FUNCüber das hinaus funcallgibt , benötigen Sie hier logischerweise keine lexikalische Bindung. Es ist nichts Falsches daran, es zu verwenden, aber Sie brauchen es nicht, es sei denn, ein Code muss tatsächlich die Variable verwenden FUNC . Wenn Sie es nicht benötigen (so sieht es bisher aus), ersetzen Sie es einfach durch seinen Wert, indem Sie backquote durch Komma verwenden.
Drew
Die lexikalische Bindung ist in Emacs 23 (und früheren Versionen) unter Verwendung von verfügbar lexical-let. Die globale Variable lexical-bindingist in Emacs 24 verfügbar.
Drew

Antworten:

5

Sie können dies lokal erreichen, indem Sie das lexikalische Zeichen von cl.el verwenden :

(eval-when-compile '(require 'cl))

(defun my-test-caller (func)
  (lexical-let ((ext-func func))
    (url-retrieve "http://www.google.com"
                  (lambda (status) (funcall ext-func)))))

(my-test-caller #'(lambda() (message "called")))

Um explizit zu sein, wie die Hilfe sagt:

Like `let', but lexically scoped.
The main visible difference is that lambdas inside BODY will create
lexical closures as in Common Lisp.

Jetzt können Sie den gleichen Effekt erzielen, indem Sie die in Emacs 24.1 hinzugefügte lexikalische Bindung aktivieren . Dies ist eine lokale Puffervariable, die festgelegt werden kann und lexikalische Schließungen für den gesamten Code im Puffer ermöglicht. Ihr Puffer würde also so aussehen:

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

(defun my-lexical-test-caller (func)
  (url-retrieve "http://www.google.com"
                (lambda (status) (funcall func))))

(my-lexical-test-caller
 #'(lambda()
     (message "called from lexical-binding def")))
stsquad
quelle
Vielen Dank. Allerdings bekomme ich my-test-caller: Symbol's function definition is void: lexical-letin meinen Emacs: GNU Emacs 24.4.1 (x86_64-w64-mingw32) `vom 20.10.2014 auf KAEL
M Smith
@MSmith - ahh hinzufügen (erfordern 'cl)
stsquad
lexical-letist definiert in cl-macs.el. Also(eval-when-compile '(require 'cl))
Drew
Sie müssen nicht zur cl.elLaufzeit benötigen , nur dafür. lexical-letist ein Makro, daher reicht es aus, es zur Kompilierungszeit zu benötigen.
Drew
2
Bitte nicht. Verwenden Sie lexical-binding. Flycheck unterstützt Emacs 23 sowieso nicht, daher macht es keinen Sinn, zu versuchen, damit kompatibel zu sein.
Mondhorn
5

Aktivieren Sie lexical-bindingfür Ihre Bibliothek mit M-x add-file-local-variable-prop-line RET lexical-binding RET t.

Bitte verwenden Sie nicht lexical-letwie in der anderen Antwort vorgeschlagen. Flycheck selbst ist nicht mit Emacs 23 kompatibel, daher macht es keinen Sinn, die Emacs 23-Kompatibilität in Ihrem eigenen Code beizubehalten.

Mondhorn
quelle
Vielen Dank. Das wird helfen, also versuche ich nicht, die älteren Emacs ohne Grund zum Laufen zu bringen
M Smith
Was ist falsch daran, lexical-let dafür zu verwenden?
stsquad
@stsquad Es ist langsamer und ausführlicher. Mit lexical-bindingbesteht keine Notwendigkeit für eine zusätzliche Bindung, weil das Argument selbst ist lexikalische. Darüber hinaus lexical-bindingwerden echte Verschlüsse erstellt, während nicht lexical-letinterinierte Symbole verwendet werden, um die lexikalische Bindung zu emulieren.
Mondhorn
@lunaryorn: Besteht kein Risiko, wenn Sie die lexikalische Bindung an einen vorhandenen Puffer mit Legacy-Code aktivieren, können unvorhergesehene Auswirkungen auftreten? Wie auch immer, ich habe meine Antwort erweitert, um beide Lösungen zu erwähnen.
stsquad
@stsquad Ja, es könnte sein , unvorhergesehene Auswirkungen auf schlecht geschriebene Legacy - Code, der auf verlässt sich letdynamisch Bindung nicht definierte Variablen. Aber auch hier ist Flycheck sowieso für Emacs 24, also sprechen wir nicht über Legacy-Code.
Mondhorn