'O valor do símbolo como variável é nulo' no retorno de chamada da recuperação de URL


8

Ao executar o seguinte, recebo um erro:

(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

Qual é a melhor maneira de resolver este problema? Basicamente, preciso aceitar um retorno de chamada de outro lugar, envolvê-lo em outro lambda e usá-lo como retorno de chamada para recuperar url.

Se eu mudar o chamador para

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

funciona. No entanto, não posso fazer isso, pois o func está sendo passado pelo flycheck e a expansão de macro o interrompe. Para ver o contexto completo do que estou fazendo: https://gist.github.com/m0smith/b5961fda6afd71e82983


Qual expansão macro? Seu último parágrafo não está claro. Poste aqui uma explicação completa do problema. O uso de aspas com vírgula é a solução (uma solução). Outro poderia ser o uso lexical-letou configuração de variável lexical-binding. Por favor, esclareça qual é o problema com a "macro" não mostrada.
Drew

Eu assumi o `e, foram macro expandidos. Qualquer que seja o nome dessa forma, então. Eu gostaria de trabalhar no EMACS 23. Existe um recurso lexical disponível?
M Smith,

Se não houver uso FUNCalém do funcallque logicamente, você não precisará de ligação lexical aqui. Não há nada errado em usá-lo, mas você não precisa , a menos que algum código realmente precise fazer uso da variável FUNC . Se você não precisar dele (como é a aparência até agora), substitua a ocorrência pelo valor, usando aspas por vírgula.
Tirou

A ligação lexical está disponível no Emacs 23 (e anterior), usando lexical-let. A variável global lexical-bindingestá disponível no Emacs 24.
Drew

Respostas:


5

Você pode conseguir isso localmente usando lexical-let do 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")))

Para ser explícito, como diz a ajuda:

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

Agora você pode obter o mesmo efeito ativando a ligação lexical que foi adicionada no Emacs 24.1. Esta é uma variável local do buffer que pode ser definida e permitirá fechamentos lexicais em todo o código no buffer. Portanto, seu buffer ficaria assim:

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

Obrigado. No entanto, eu entro my-test-caller: Symbol's function definition is void: lexical-letno meu emacs: GNU Emacs 24.4.1 (x86_64-w64-mingw32) `of 2014-10-20 on KAEL
M Smith

@MSmith - ahh add (require 'cl)
stsquad

lexical-leté definido em cl-macs.el. Então(eval-when-compile '(require 'cl))
de Drew

Você não precisa exigir cl.elem tempo de execução, apenas para isso. lexical-leté uma macro, portanto é suficiente exigir isso em tempo de compilação.
Tirou

2
Por favor não. Use lexical-binding. O Flycheck não suporta o Emacs 23 de qualquer maneira, então não faz sentido tentar ser compatível com ele.
lunaryorn

5

Ative lexical-bindingpara sua biblioteca, com M-x add-file-local-variable-prop-line RET lexical-binding RET t.

Por favor, não use lexical-letcomo sugerido pela outra resposta. O Flycheck em si não é compatível com o Emacs 23, portanto, não faz sentido tentar manter a compatibilidade do Emacs 23 em seu próprio código.


Obrigado. Isso vai ajudar para que eu não estou tentando obter os emacs mais velhos funcionar sem motivo
M Smith

O que há de errado em usar lexical-let para isso?
Stsquad 11/11/14

@stsquad É mais lento e detalhado. Com isso, lexical-bindingnão há necessidade de uma ligação adicional, porque o argumento em si tem um escopo lexicamente. Além disso, lexical-bindingcria verdadeiros fechamentos, enquanto lexical-letusa símbolos não internos para emular a ligação lexical.
Lunardorn 11/11

@ lunaryorn: não há risco ao ativar a ligação lexical em um buffer existente de código legado para obter efeitos imprevisíveis? Enfim, ampliei minha resposta para mencionar as duas soluções.
Stsquad

@stsquad Sim, pode haver efeitos imprevistos no código legado mal escrito, que depende da letligação dinâmica de variáveis ​​indefinidas. Mas, novamente, Flycheck é para o Emacs 24 de qualquer maneira, por isso não estamos falando de código legado.
lunaryorn
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.