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

Почему резкие цитаты лямбда-выражения?

Это часто используется метод On Lisp, который находится в Common Lisp:

> (mapcar #'(lambda (x) (+ x 10))
         '(1 2 3))
(11 12 13)

Почему резкая цитата нужна или даже возможна? лямбда-выражения возвращают функциональные объекты, а резкое цитирование возвращает объекты функции из имен. Я также слышал противоречивую информацию о том, являются ли лямбда-выражения именами, в частности On Lisp, противоречит стандарту, но его код, похоже, работает, что также противоречит стандарту.

В elisp кажется, что это не нужно вообще. К моему удивлению, это не включало в себя обсуждение лексического охвата, поэтому непонятно, почему он вообще должен отличаться от Common Lisp. Но этот ответ говорит о том, что некорректные лямбда-выражения не имеют никакого смысла, поэтому, по иронии судьбы, можно было вводить некотируемые лямбда-выражения в качестве синтаксического сахара для цитируемых. Но это противоречит инструкции elisp вручную: "В Emacs Lisp такой список является допустимым выражением, которое оценивает объект функции".

Этот вопрос помечен как common-, так и e- Lisp, потому что я пытаюсь понять теоретическую модель, лежащую в основе обоих, и изучать их, изучая их различия. (Более практично я пытаюсь изучить elisp, но нашел много хороших ресурсов на Common Lisp, поэтому я учусь изучению обоих).

4b9b3361

Ответ 1

Предполагается общий Lisp.

Почему нужна или даже возможна острая цитата?

Если вы хотите вычислить объект функции из имени функции (особенно если вы хотите ссылаться на лексическую привязку) или лямбда-выражения, вам нужен специальный оператор FUNCTION или более короткий #'.

лямбда-выражения возвращают функциональные объекты,

Они этого не делают. Лямбда-выражения не могут быть оценены.

В Common Lisp он выглядит как (lambda () nil). Но он не может.

Когда-то после CLtL1 был добавлен макрос LAMBDA, который расширяет его до выражения (FUNCTION ...). Этот макрос сохраняет некоторую типизацию и позволяет коду выглядеть немного более похожим на Scheme. Проверьте этот макрос LAMBDA:

CL-USER 17 > (macroexpand-1 '(lambda () ()))  ; not a lambda expression
(FUNCTION 
  (LAMBDA NIL NIL)                            ; <- this is a lambda expression
)
T

Это означает, что при оценке (lambda () ()):

выполняется следующее:
  • LAMBDA - макрос. Таким образом, форма расширяется до (function (lambda () ())).
  • (function (lambda () ()))FUNCTION - специальный оператор. Он возвращает объект функции

Если вы пишете: #'(lambda () ()) или (function (lambda () ())), вы пропустите расширение макроса.

Хорошо, теперь для чего-то странного:

CL-USER 18 > (lambda () ())   ; <- this is not a lambda expression.
                              ;    it a macro form, see above 
#<anonymous interpreted function 40600009FC>

Поскольку выше макрос, он будет сначала раскрыт, а затем он может быть оценен.

CL-USER 19 > (function          ; <- this is a special form
              (lambda () ())    ; <- this is a lambda expression
              )
#<anonymous interpreted function 4060000C0C>

Здесь это действительно лямбда-выражение. Внутри специального оператора FUNCTION форма не будет расширена макросом или аналогичной.

CL-USER 20 > (                  ; <- this is a function call
              (lambda () ())    ; <- this is a lambda expression
              )

Выше снова показано лямбда-выражение. Где ((function (lambda () ()))) недействительно. Общий Lisp. В функциональном положении вызова функции Common Lisp ожидает либо имя функции, либо лямбда-выражение, но не то, что необходимо оценить.

и резкое цитирование возвращает объекты функции из имен.

FUNCTION, для которого #' является короткой нотацией, возвращает функциональные объекты из имен функций или лямбда-выражения.

Смотрите документацию: ФУНКЦИЯ.

Я также слышал противоречивую информацию о том, являются ли лямбда-выражения именами, в частности On Lisp, противоречит стандарту, но его код, похоже, работает, что также противоречит стандарту.

Если вы хотите услышать последнее слово, прочитайте стандарт ANSI CL. В качестве альтернативы можно использовать Common Lisp Hyperspec, который является удобочитаемым и выводимым из стандарта.

В Lisp определенно полезно читать, но может не следовать формулировке или семантике ANSI CL полностью. На Lisp был опубликован после CLtL2, но до ANSI CL.

Что это означает практически при написании кода?

Если вы стары, как и я, а CLtL1 - это последнее, что вы читаете в Common Lisp, тогда напишите код наподобие:

(mapcar #'(lambda (x) (* x x)) '(1 2 3))

Если вы еще старше и выросли вместе с Scheme, или моложе, и прочитали Common Lisp Hyperspec, тогда вы можете написать:

(mapcar (lambda (x) (* x x)) '(1 2 3))

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

(mapcar #'sin '(1 2 3))

Ответ 2

Короче говоря, вам не нужно делать резкую цитату lambda, потому что это макрос, который расширяется до (function (lambda ...)), и он function выполняет всю магию.

Единственный смысл, в котором function не нужен, состоит в том, что вам не нужно вводить его самостоятельно. Это function, а не lambda, т.е. Фундаментальный оператор. Лямбда-выражения сами по себе являются обычными списками (которые function знают, как превращаться в объекты функций), а lambda - это просто обычный макрос. Таким образом, у вас есть вещи скорее назад: эти лямбда-выражения возвращают функциональные объекты, не устраняют function, потому что lambda объясняется в терминах function.

Дополнительная морщина заключается в том, что в Emacs Lisp списки, начинающиеся с lambda, могут рассматриваться как функции напрямую, без прохождения function. Это не так в CL (хотя явное преобразование доступно в виде (coerce some-list 'function)).

Ответ 3

Все это связано с историей. (lambda ...) - это просто синтаксический сахар для #'(lambda ..). В более ранних версиях Common Lisp не было lambda, определяемого как макрос. Например. если вы прочтете эссе Роберта Норвига о Quines (PD, page2), вы видите, что он явно заявляет, что вам нужно создать такой макрос следующим образом:

(defmacro lambda (args &body body)
  "Allow (lambda (x) ...) instead of #’(lambda (x) ...)"
  ‘#’(lambda ,args .,body))

Таким образом, при записи (lambda ...) сегодня стандартный макрос переписывает его на #'(lambda ...).

В Lisp старая книга, и она, возможно, была опубликована до того, как макрос стал стандартным. Также может быть, что Пол Грэхем используется для записи #'(lambda ...) и застрял с ним.

Я видел, что более поздние издания компьютерных книг часто меняются как можно меньше, когда они соответствуют новому стандарту. Я не уверен, что это хорошо.

Ответ 4

Ключевое слово function, по-видимому, имеет разные значения на разных языках Lisp.

В Lisp 1.5 он использовался для создания замыкания с использованием устройства funarg. Ссылка: http://c2.com/cgi/wiki?DynamicClosure и руководство по программированию Lisp 1.5, Приложение B.

В MacLisp он использовался как подсказка для компилятора, чтобы сказать, что выражение лямбда может быть скомпилировано как код. Ссылка: Питман, 7. Формы определения. Он не использовался для создания закрытий; специальная форма *function сделала нечто подобное. Ссылка The Pitmanual, 3. Оценщик.

В Emacs Lisp он является подсказкой для компилятора и также может создавать лексические замыкания. Ссылка: Справочное руководство Emacs Lisp, 12.7 Анонимные функции.