Формат лямбды в 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:
Обратите внимание, что вы могли бы определить 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.