'El valor del símbolo como variable es nulo' en la devolución de llamada de url-retrieve

8

Al ejecutar lo siguiente me sale un error:

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


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

Resultado:

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

¿Cuál es la mejor manera de resolver este problema? Básicamente, necesito aceptar una devolución de llamada de otro lugar, envolverla en otra lambda y usarla como devolución de llamada para recuperar URL.

Si cambio la llamada a

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

funciona. Sin embargo, no puedo hacer esto ya que flycheck pasa la función y la expansión de macro la rompe. Para ver el contexto completo de lo que estoy haciendo: https://gist.github.com/m0smith/b5961fda6afd71e82983

M Smith
fuente
¿Qué macro expansión? Tu último párrafo no está claro. Publique aquí una explicación completa del problema. Usar backquote con coma es la solución (una solución). Otro podría ser usar lexical-leto configurar variables lexical-binding. Por favor, aclare cuál es el problema con la "macro" no mostrada.
Dibujó el
Asumí el `y, fueron macro expandidos. Como se llame esa forma entonces. Me gustaría trabajar en EMACS 23. ¿Hay alguna función léxica disponible?
M Smith
Si no hay uso FUNCmás allá del funcalllógico, entonces no necesita enlace léxico aquí. No hay nada de malo en usarlo, pero no lo necesita , a menos que algún código realmente necesite hacer uso de la variable FUNC . Si no lo necesita (que es lo que parece hasta ahora), simplemente reemplace su ocurrencia por su valor, utilizando comillas y comillas.
Dibujó el
El enlace léxico está disponible en Emacs 23 (y anteriores), utilizando lexical-let. La variable global lexical-bindingestá disponible en Emacs 24.
Drew

Respuestas:

5

Puede lograr esto localmente usando cl.el's lexical-let :

(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")))

Para ser explícito como dice la ayuda:

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

Ahora puede obtener el mismo efecto habilitando el enlace léxico que se agregó en Emacs 24.1. Esta es una variable local del búfer que se puede configurar y habilitará los cierres léxicos en todo el código del búfer. Entonces su búfer se vería así:

;; -*- 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
fuente
Gracias. Sin embargo, me meto my-test-caller: Symbol's function definition is void: lexical-leten mis emacs: GNU Emacs 24.4.1 (x86_64-w64-mingw32) `de 2014-10-20 en KAEL
M Smith
@MSmith - ahh add (require 'cl)
stsquad
lexical-letse define en cl-macs.el. Entonces(eval-when-compile '(require 'cl))
Drew
No necesita exigir cl.elen tiempo de ejecución, solo para esto. lexical-letes una macro, por lo que es suficiente requerirla en tiempo de compilación.
Dibujó el
2
Por favor no lo hagas. Uso lexical-binding. Flycheck no es compatible con Emacs 23 de todos modos, por lo que no tiene sentido tratar de ser compatible con él.
lunaryorn
5

Habilite lexical-bindingpara su biblioteca, con M-x add-file-local-variable-prop-line RET lexical-binding RET t.

Por favor no use lexical-letcomo lo sugiere la otra respuesta. Flycheck en sí mismo no es compatible con Emacs 23, por lo que no tiene sentido tratar de mantener la compatibilidad con Emacs 23 en su propio código.

Lunaryorn
fuente
Gracias. Eso ayudará, así que no estoy tratando de hacer que los emacs más antiguos funcionen sin ninguna razón
M Smith
¿Qué hay de malo en usar lexical-let para esto?
stsquad
@stsquad Es más lento y más detallado. Con lexical-bindingno hay necesidad de un enlace adicional, porque el argumento en sí mismo tiene un alcance léxico. Además, lexical-bindingcrea cierres verdaderos, mientras que lexical-letusa símbolos no intercalados para emular el enlace léxico.
lunaryorn
@lunaryorn: ¿no existe un riesgo al habilitar el enlace léxico en un búfer existente de código heredado que puede obtener efectos imprevistos? De todos modos, he ampliado mi respuesta para mencionar ambas soluciones.
stsquad
@stsquad Sí, podría haber efectos imprevistos en el código heredado mal escrito que se basa en la letvinculación dinámica de variables indefinidas. Pero, de nuevo, Flycheck es para Emacs 24 de todos modos, por lo que no estamos hablando de código heredado.
lunaryorn