如何克服emacs lisp闭包缺少局部变量

时间:2011-08-05 11:29:36

标签: emacs lisp elisp common-lisp dynamic-scope

我现在正在研究reference manual中的LISP和Common Lisp中的Emacs Lisp。

来自Common Lisp的书

>> (setf power-of-two
     (let ((previous-power-of-two 1))
       #'(lambda ()
           (setf previous-power-of-two
             (* previous-power-of-two 2)))))

>> (funcall power-of-two)
2

>> (funcall power-of-two)
4

>> (funcall power-of-two)
8

由于其动态绑定行为,该函数在Emacs Lisp中不起作用。

我想知道是否可以在不引入全局变量的情况下在Emacs Lisp中实现相同的功能?

4 个答案:

答案 0 :(得分:17)

更新

到目前为止,Emacs 24已正式发布,当缓冲区局部变量lexical-let为非零时,它支持词法绑定而不使用lexical-binding。另见M-: (info "(elisp) using lexical binding")和pokita的答案。


您可以使用Common Lisp Extensions中的lexical-let(“CL套餐”):

elisp> (require 'cl)
cl
elisp> (setf power-of-two
             (lexical-let ((previous-power-of-two 1))
               #'(lambda ()
                   (setf previous-power-of-two
                         (* previous-power-of-two 2)))))
(lambda
  (&rest --cl-rest--)
  (apply
   (lambda
     (G175638)
     (set G175638
          (*
           (symbol-value G175638)
           2)))
   '--previous-power-of-two-- --cl-rest--))

elisp> (funcall power-of-two)
2
elisp> (funcall power-of-two)
4
elisp> (funcall power-of-two)
8

我也听说过GNU Emacs的lexbind分支。

答案 1 :(得分:12)

bzr的Emacs24现在支持开箱即用的词法绑定;它只是默认情况下没有被激活,因为有许多软件包仍然故意或无意中依赖于动态范围。您的上述代码应该在Emacs24中在缓冲区中正常工作,其中变量'lexical-binding'设置为't'。

答案 2 :(得分:2)

答案 3 :(得分:1)

使用Emacs的unintern符号的另一种解决方案:

ELISP> (setf power-of-two
         (let ((p (make-symbol "previous-power-of-two")))
           (set p 1) (list 'lambda '()
           (list 'setf p
             (list '* p 2)))))

ELISP> (funcall power-of-two)
2
ELISP> (funcall power-of-two)
4
ELISP> (funcall power-of-two)
8