'La valeur du symbole en tant que variable est nulle' dans le rappel depuis url-retrieve


8

Lors de l'exécution de ce qui suit, j'obtiens une erreur:

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


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

Résultat:

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

Quelle est la meilleure façon de résoudre ce problème? Fondamentalement, je dois accepter un rappel ailleurs, l'envelopper dans un autre lambda et l'utiliser comme rappel pour récupérer l'URL.

Si je change l'appelant en

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

Ça marche. Cependant, je ne peux pas le faire car le func est passé par flycheck et l'expansion de la macro le brise. Pour voir le contexte complet de ce que je fais: https://gist.github.com/m0smith/b5961fda6afd71e82983


Quelle macro expansion? Votre dernier paragraphe n'est pas clair. Postez ici une explication complète du problème. L'utilisation de backquote avec virgule est la solution (une solution). Un autre pourrait être d'utiliser lexical-letou de définir une variable lexical-binding. Veuillez clarifier le problème avec la "macro" non affichée.
Drew

J'ai supposé que le `et, étaient macro élargi. Quel que soit le nom de cette forme, alors. J'aimerais travailler dans EMACS 23. Y a-t-il une fonction lexicale disponible?
M Smith,

S'il n'y a pas d'utilisation d' FUNCau-delà, funcallalors logiquement, vous n'avez pas besoin de liaison lexicale ici. Il n'y a rien de mal à l'utiliser, mais vous n'en avez pas besoin , sauf si du code doit réellement utiliser la variable FUNC . Si vous n'en avez pas besoin (ce à quoi il ressemble jusqu'à présent), remplacez simplement son occurrence par sa valeur, en utilisant backquote avec une virgule.
Drew

La reliure lexicale est disponible dans Emacs 23 (et versions antérieures), en utilisant lexical-let. La variable globale lexical-bindingest disponible dans Emacs 24.
Drew

Réponses:


5

Vous pouvez y parvenir localement en utilisant le lexical-let de cl.el :

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

Pour être explicite comme le dit l'aide:

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

Vous pouvez maintenant obtenir le même effet en activant la liaison lexicale qui a été ajoutée dans Emacs 24.1. Il s'agit d'une variable locale de tampon qui peut être définie et permettra des fermetures lexicales sur tout le code du tampon. Ainsi, votre tampon ressemblerait à ceci:

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

Merci. Cependant je reçois my-test-caller: Symbol's function definition is void: lexical-letdans mes emacs: GNU Emacs 24.4.1 (x86_64-w64-mingw32) `du 2014-10-20 sur KAEL
M Smith

@MSmith - ahh add (require 'cl)
stsquad

lexical-letest défini dans cl-macs.el. Donc(eval-when-compile '(require 'cl))
Drew

Vous n'avez pas besoin d'exiger cl.elau moment de l'exécution, juste pour cela. lexical-letest une macro, il suffit donc de l'exiger au moment de la compilation.
Drew

2
S'il vous plait, ne le faites pas. Utilisez lexical-binding. Flycheck ne prend pas en charge Emacs 23 de toute façon, il est donc inutile d'essayer d'être compatible avec lui.
lunaryorn

5

Activer lexical-bindingpour votre bibliothèque, avec M-x add-file-local-variable-prop-line RET lexical-binding RET t.

Veuillez ne pas utiliser lexical-letcomme suggéré par l'autre réponse. Flycheck lui-même n'est pas compatible avec Emacs 23, il est donc inutile d'essayer de maintenir la compatibilité Emacs 23 dans votre propre code.


Merci. Cela aidera donc je n'essaye pas de faire fonctionner les anciens emacs sans raison
M Smith

Quel est le problème avec lexical-let pour cela?
stsquad

@stsquad C'est plus lent et plus verbeux. Avec lexical-bindingil n'y a pas besoin d'une liaison supplémentaire, car l'argument lui-même a une portée lexicale. De plus, lexical-bindingcrée de véritables fermetures, alors qu'il lexical-letutilise des symboles non internes pour émuler la liaison lexicale.
lunaryorn

@lunaryorn: n'y a-t-il pas un risque en activant la liaison lexicale sur un tampon existant de code hérité, vous pouvez obtenir des effets imprévus? Quoi qu'il en soit, j'ai élargi ma réponse pour mentionner les deux solutions.
stsquad

@stsquad Oui, il pourrait y avoir des effets imprévus dans un code hérité mal écrit qui repose sur la letliaison dynamique de variables non définies. Mais encore une fois, Flycheck est pour Emacs 24 de toute façon, nous ne parlons donc pas de code hérité.
lunaryorn
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.