2009-07-28 2 views
33

Я не знаю, если вы могли бы назвать его канонической формулировку, но связать локальную функцию я консультировал в руководстве GNU использовать «FLET»:пусть и FLET в Emacs Lisp

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

+0

Для тех, кто пытается это, обратите внимание, что 'flet' не может быть доступны в версии Emacs, которые вы используете, в этом случае попробуйте' (требуешься «клы) 'заранее, как указано ниже (' flet' - это CommonLisp thingy). – Robert

+0

В каком руководстве GNU рекомендуется использовать 'flet' здесь? – Stefan

+1

От Emacs 25.1.1 Опишите функцию: flet Этот макрос устарел с 24.3; используйте 'cl-flet 'или' cl-letf' – AAAfarmclub

ответ

37

В отличие от Схемы, 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

+0

Спасибо за объяснение! Я вижу, что это различие между поиском ценности и функцией-поиском. Я был знаком с соглашением о наличии отдельных пространств имен для функций и переменных, но не смог связать это с тем, как функция, связанная как переменная, может вызываться mapcar *. – hatmatrix

18

Я сделал быстрый поиск в Emacs Lisp вручную и не смогли найти никаких ссылок на 'flet, что не очень удивительно, поскольку это является частью cl - common-lisp package.

let также будет выполнять локальную привязку, но для этого символа не будет привязан к "function cell".

т.е. это работает:

(let ((myf (lambda (x) (list x x)))) 
    (eval (list myf 3))) 

но

(let ((myf (lambda (x) (list x x)))) 
    (myf 3)) 

завершается с ошибкой: "Лисп ошибка: (аннулируется-функция MYF)"

flet с другой стороны, делает сделайте привязку к функциональной ячейке, поэтому это работает:

(flet ((myf (x) (list x x))) 
    (myf 3)) 

Обратите внимание, что разница в том, что flet позволяет использовать символ myf напрямую, в то время как у let нет - вам нужно использовать некоторую косвенность, чтобы получить функцию из ячейки значений и применить ее соответствующим образом.

В вашем примере «mapcar» сделал эквивалент моему использованию 'eval.

+0

Спасибо за ваш ответ! Вместе с объяснением Зиелэя я вижу, как это работает «eval». Да, flet, похоже, находится в расширении cl; Я изначально прочитал, что (требуется «cl»), прежде чем использовать flet, но я думаю, что в новых emacs это уже не так ... – hatmatrix

+5

Прежде чем расширение 'cl' было отправлено Emacs из коробки, как люди описать функции функций, которые необходимо объявить с помощью семантики let-like? Было ли принято, что eval - это способ сделать это? – d11wtq

7

@ d11wq есть `FUNCALL» для этой цели. Следующие работы:

(defun adder-with-let (x) 
    (let ((f #'(lambda (x) (+ x 3)))) 
    (funcall f 3))) 

(adder-with-let 3) ;=> 6 
0

Вы не должны использовать flet, если вы не хотите. Вы помещаете функцию в функции ячейке локального символа, определенный с помощью let, как в следующем примере:

(let ((ALocalSymbol)) 
    (fset 'ALocalSymbol (lambda (x) (* 2 x))) 
    (ALocalSymbol 4) 
) 

Оценка это вернет 8. Не замечает цитату перед ALocalSymbol в (let ((ALocalSymbol))...). В то время как setq цитирует символы, fset нет.

flet является синтаксическим сахаром. Использование простого let для определения нулевых символов позволяет вам выбрать, какая «ячейка» установленного символа. Вы можете использовать setq для установки ячейки значения символа или fset для установки ячейки функции.

Надеется, что это помогает,

Пабло

+0

Это совершенно неправильно и связывает (одну) глобальную функциональную ячейку для интернированного символа 'ALocalSymbol'. (Только ячейки * value * привязаны.) Это можно сделать, если вы создавали * новый * (неинтерминированный) символ, а не просто привязывали (значение) интернированный символ. – phils

+0

Для ясности: Этот код определяет функцию 'ALocalSymbol' в пространстве имен глобальных функций. Если функция с таким именем уже определена, она сбивается. – phils

+0

Обратите внимание также, что если бы вы создали неинтерминированный символ, '(ALocalSymbol 4)' все равно вызывал бы функцию интернированного символа, поэтому вам нужно было бы «funcall» (или аналогичный) ваш uninterned symbol/function. – phils

 Смежные вопросы

  • Нет связанных вопросов^_^