Формат лямбды в emacs lisp

Я пытаюсь применить замыкание в emacs lisp. И я нахожу здесь пост: Как мне сделать замыкания в Emacs Lisp?

с некоторым кодом, как:

(defun foo (x) `(lambda (), x)) (сообщение (строка (funcall (foo 66))))

Но, следуя документации emacs, лямбда должна быть отформатирована как '(lambda () x) ==>, используя этот формат, я получил ОШИБКУ: значение символа в качестве переменной равно void: x

Когда "," добавить между "()" и "х", все идет хорошо.

Зачем?

1 ответ

Решение

Это происходит потому, что Emacs Lisp динамически ограничен foo возвращает лямбда где x это бесплатно. Вот что говорит вам ошибка.

Чтобы сделать замыкание в Emacs Lisp, вы должны использовать lexical-let который имитирует лексическое связывание и, следовательно, позволяет сделать реальное закрытие.

(defun foo (x)
  (lexical-let ((x x))
               (lambda () x)))

(message (string (funcall (foo 66))))

Вот несколько ссылок из Emacs Wiki:

  1. Динамическое связывание и лексическое связывание
  2. Поддельные закрытия

Обратите внимание, что вы могли бы определить x с таким вот пусть:

(defun foo (x)
  (lambda () x))

(message (string (let ((x 66)) (funcall 
                                (foo 'i-dont-care)))))

Этот ответ дает немного подробностей о первой части правильного ответа @Daimrod.

Ваш вопрос, почему это работает:

(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))

и это не работает:

(defun foo (x) '(lambda () x)) (message (string (funcall (foo 66))))

Во-первых, цитата (') во втором случае не требуется, потому что в Emacs Lisp лямбда-формы являются самооценочными. То есть,'(lambda (...) ...) обычно действует так же, как (lambda (...) ...).

Но при чем здесь обратная цитата (`) вместо цитаты (') делать?

Внутри выражения в обратной кавычке запятая (,) означает заменить следующее выражение его значением, то есть оценить его. Итак, это:

`(lambda () ,x)

означает создание и возврат списка, первым элементом которого является символ lambda (это не оценивается), второй элемент которого ()(это не оценивается), и чей третий элемент является значением переменнойx. Это эквивалентно оценке этого кода, в котором используется функцияlist:

(list 'lambda '() x)

Это то, что вы хотите: заменить x его текущим значением (в данном случае его значением внутри функции foo, то есть значение fooаргумент).

Но это:

'(lambda () x)

(и аналогично, поскольку лямбда-форма является самооценкой, (lambda () x)) возвращает этот список: (lambda () x). И когда это оценивается с использованием динамической области видимости (режим области видимости по умолчанию в Emacs Lisp),xнесвязан - не имеет значения. Таким образом возникает ошибка void-variable.

Другие вопросы по тегам