¿Cómo hago cierres en Emacs Lisp?

Intento crear una función sobre la marcha que devuelva un valor constante.

En JavaScript y otros lenguajes imperativos modernos usaría cierres:

function id(a) { return function() {return a;}; } 

pero Emacs lisp no los admite.

Puedo crear una combinación de función de identidad y aplicación de función parcial, pero tampoco es compatible.

Entonces, ¿cómo hago eso?

Idea estúpida: ¿qué tal:

 (defun foo (x) `(lambda () ,x)) (funcall (foo 10)) ;; => 10 

Encontré otra solución con lexical-let

 (defun foo (n) (lexical-let ((nn)) #'(lambda() n))) (funcall (foo 10)) ;; => 10 

Cierres reales (no falsos) en Emacs 24.

Aunque Emacs 24 tiene extracción léxica cuando la variable de vinculación léxica tiene un valor t , la forma especial defun no funciona correctamente en contextos ligados léxicamente (al menos no en Emacs 24.2.1.) Esto hace que sea difícil, pero no imposible, definir cierres reales (no falsos). Por ejemplo:

 (let ((counter 0)) (defun counting () (setq counter (1+ counter)))) 

no funcionará como se espera porque el contador de símbolos en el defun se vinculará a la variable global de ese nombre, si hay uno, y no a la variable léxica definida en let . Cuando se llama el conteo de funciones, si la variable global no existe, entonces obviamente fallará. Sin embargo, si hay una variable global así se actualizará, lo que probablemente no sea lo que se pretendía y podría ser un error difícil de rastrear, ya que la función podría funcionar correctamente.

El comstackdor de bytes da una advertencia si utiliza defun de esta manera y, presumiblemente, el problema se tratará en alguna versión futura de Emacs, pero hasta entonces se puede usar la siguiente macro:

 (defmacro defun** (name args &rest body) "Define NAME as a function in a lexically bound context. Like normal `defun', except that it works correctly in lexically bound contexts. \(fn NAME ARGLIST [DOCSTRING] BODY...)" (let ((bound-as-var (boundp `,name))) (when (fboundp `,name) (message "Redefining function/macro: %s" `,name)) (append `(progn (defvar ,name nil) (fset (quote ,name) (lambda (,@args) ,@body))) (if bound-as-var 'nil `((makunbound `,name)))))) 

Si define conteo de la siguiente manera:

 (let ((counter 0)) (defun** counting () (setq counter (1+ counter)))) 

funcionará según lo esperado y actualizará el recuento de variables vinculadas léxicamente cada vez que se invoca, mientras devuelve el nuevo valor.

CAVEAT: La macro no funcionará correctamente si intenta desactivar ** una función con el mismo nombre que una de las variables ligadas léxicamente. Es decir, si haces algo como:

 (let ((dont-do-this 10)) (defun** dont-do-this () ......... .........)) 

No puedo imaginar a nadie que realmente lo haga, pero valió la pena mencionarlo.

Nota: He llamado a la macro defun ** para que no entre en conflicto con la macro defun * en el paquete cl , sin embargo, no depende de ninguna manera de ese paquete.

Emacs lisp solo tiene un scope dynamic. Hay una macro de lexical-let que aproxima el scope léxico a través de un truco bastante terrible.

No soy firme en Emacs Lisp, pero hasta donde yo sé, una gran diferencia con Common Lisp es que utiliza un scope dynamic en todo momento. El Manual de Emacs Lisp establece que Emacs Lisp no tiene cierres.

Trataré de aplicar mis conocimientos teóricos del scope dynamic.

Si tiene un id función que solo devuelve el valor de my-id :

 (defun id ()
   mi identificación)

y lo usas en alguna otra función:

 (defun-some-other-place ()
   (carné de identidad))

y en algún lugar en el camino a la llamada de id se une my-id través de, por ejemplo, un let:

 (defun even-elsewhere)
   (let ((my-id 5))
     (algún otro lugar)))

esto debería devolver 5.

Sé que el scope dynamic es una bestia extraña cuando estás acostumbrado al scope léxico, pero quizás puedas usar esto para implementar tu comportamiento deseado.

Emacs 24 tiene unión léxica.

http://www.emacswiki.org/emacs/LexicalBinding