Let и flet в emacs lisp
Я не знаю, назовете ли вы его канонической формулировкой, но привяжите локальную функцию. В руководстве GNU я рекомендую использовать "flet":
(defun adder-with-flet (x)
(flet ( (f (x) (+ x 3)) )
(f x))
)
Однако случайно я попробовал (после того, как немного проиграл в Схеме) следующее выражение, где я привязываю выражение лямбда к переменной с помощью "let", а также работает, если передать функцию mapcar *:
(defun adder-with-let (x)
(let ( (f (lambda (x) (+ x 3))) )
(car (mapcar* f (list x)) ))
)
И обе функции работают:
(adder-with-flet 3) ==> 6
(adder-with-let 3) ==> 6
Почему вторая работает? Я не могу найти документацию, где 'let' может использоваться для привязки функций к символам.
Ответы
Ответ 1
В отличие от Схемы, Emacs Lisp является 2- lisp, что означает, что каждый символ имеет два отдельных привязки: привязку значения и привязку функции. В вызове функции (a b c d)
первый символ (a
) просматривается с использованием привязки функции, остальные (b c d
) просматриваются с использованием привязки значения. Специальная форма let
создает новое (локальное) связывание значений, flet
создает новую привязку функции.
Обратите внимание, что использование привязки значения или функции для поиска зависит от позиции в вызове функции (a b c d)
, а не от типа искаженного значения. В частности, привязка значения может разрешиться для работы.
В первом примере вы связываете функцию f
(через flet
), а затем выполняете поиск по функциям:
(f ...)
В вашем втором примере вы привязываете значение f
к функции (через let
), а затем используйте поиск по значению:
(... f ...)
Оба работают, потому что вы используете один и тот же тип привязки и поиска в каждом случае.
http://en.wikipedia.org/wiki/Common_Lisp#Comparison_with_other_Lisps
Ответ 2
Я быстро просмотрел руководство Emacs lisp и не нашел ссылки на 'flet
, что не удивительно, поскольку это часть cl
- общий lisp пакет.
let
также будет выполнять локальную привязку, но не привязывается к "function cell" для этого символа.
то есть. Это работает:
(let ((myf (lambda (x) (list x x))))
(eval (list myf 3)))
но
(let ((myf (lambda (x) (list x x))))
(myf 3))
не работает с ошибкой: "Lisp error: (void-function myf)"
flet
, с другой стороны, выполняет привязку к ячейке функции, поэтому это работает:
(flet ((myf (x) (list x x)))
(myf 3))
Обратите внимание на то, что flet
позволяет использовать символ myf
напрямую, а let
- нет - вам нужно использовать некоторую косвенность, чтобы вывести функцию из ячейки значений и применить ее соответственно.
В вашем примере "mapcar
" сделал эквивалент моего использования 'eval
.
Ответ 3
@d11wq для этой цели существует "funcall". Следующие работы:
(defun adder-with-let (x)
(let ((f #'(lambda (x) (+ x 3))))
(funcall f 3)))
(adder-with-let 3) ;=> 6
Ответ 4
Вам не нужно использовать flet
, если вы этого не хотите. Вы помещаете функцию в ячейку функции локального символа, определенного с помощью let
, как в следующем примере:
(let ((ALocalSymbol))
(fset 'ALocalSymbol (lambda (x) (* 2 x)))
(ALocalSymbol 4)
)
Оценка этого значения вернется 8. Обратите внимание на цитату перед ALocalSymbol
в (let ((ALocalSymbol))...)
. Пока setq
цитирует символы, fset
не делает.
flet
является синтаксическим сахаром. Использование простого let
для определения nil-значных символов позволяет вам выбрать, какая ячейка установленного символа. Вы можете использовать setq
, чтобы установить ячейку символьного значения или fset
, чтобы установить ячейку функции.
Надеюсь, что это поможет,
Пабло