Как преодолеть отсутствие локальной переменной для закрытия emacs lisp - PullRequest
10 голосов
/ 05 августа 2011

Я сейчас изучаю Emacs Lisp из справочного руководства и Common Lisp из LISP Book.

из книги 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 ]

17 голосов
/ 05 августа 2011

Обновление:

К настоящему времени Emacs 24 официально выпущен и поддерживает лексическое связывание без использования lexical-let, когда локальная переменная буфера lexical-binding не равна нулю. Смотрите также M-: (info "(elisp) using lexical binding") и ответ покиты.


Вы можете использовать lexical-let из Common Lisp Extensions («пакет 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

Я также слышал о ветке lexbind в GNU Emacs.

12 голосов
/ 05 августа 2011

Emacs24 от bzr теперь поддерживает лексическое связывание из коробки;он просто не активирован по умолчанию, так как есть много пакетов, которые все еще намеренно или непреднамеренно зависят от динамической области видимости.Приведенный выше код должен нормально работать в Emacs24 в буфере, где переменная 'lexical-binding' установлена ​​в 't'.

2 голосов
/ 10 сентября 2011

см. Эту страницу: http://www.emacswiki.org/emacs/FakeClosures

1 голос
/ 12 декабря 2011

другое решение с использованием символа Emacs:

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
...