Подтвердить что ты не робот

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' может использоваться для привязки функций к символам.

4b9b3361

Ответ 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, чтобы установить ячейку функции.

Надеюсь, что это поможет,

Пабло