'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

M Smith
fonte
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")))
stsquad
fonte
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.

lunaryorn
fonte
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