Почему лямбда-выражение Common-Lisp является допустимым именем функции? - PullRequest
0 голосов
/ 16 января 2019

Итак, допустим, я хочу вызвать некоторую функцию. Если я определил функцию с помощью defun, я просто использую имя функции в начале списка, за которым следуют ее аргументы, например так (я буду использовать «=>» в примерах, чтобы показать вывод ввода кода в ответный ответ):

(defun f (a) (lambda (b) (+ a b))) => F
(f 12) => #<FUNCTION :LAMBDA (B) (+ A B)>

Достаточно просто. Первым элементом списка должно быть имя функции, специального оператора или макроса. Кроме того, действует также следующее:

((lambda (a) (+ a 12)) 1) => 13

Быстрый поиск в Google показывает, что LAMBDA - это и символ, и макрос. Попытка расширить макрос дает:

(macroexpand '(lambda (a) (+ a 12))) => #'(LAMBDA (A) (+ A 12))

Это не полезно. У меня нет возможности провести различие между макросом LAMBDA и символом LAMBDA, и мне совершенно неясно, почему я могу использовать лямбда-выражение в качестве имени функции, но не, скажем, # 'f, что, насколько мне известно, следует оценить действительное обозначение функции для функции F так же, как # '(LAMBDA (A) (+ A 12)), и все же:

(#'f 12) => *** - EVAL: #'F is not a function name; try using a symbol instead

Является ли LAMBDA особым исключением из жестко заданного правила, согласно которому первый элемент оцениваемого выражения должен быть именем какой-либо операции, или существует более последовательный набор правил, который я неправильно понимаю?

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Лямбда-выражения и имена функций

A Лямбда-выражение не является именем функции . имена функций в Common Lisp определены как символы или (символ setf) . лямбда-выражение в основном является встроенным синтаксисом для описания анонимной функции.

Обратите внимание, что лямбда-выражения сами по себе не имеют смысла в Common Lisp.Они появляются только в лямбда-форме (см. Ниже) и внутри формы со специальным оператором function.

Списки в виде форм

Является ли LAMBDA особым исключением из жестко установленного правила, согласно которому первый элемент вычисляемого выражения должен быть именем некоторогооперация, или есть какой-то более непротиворечивый набор правил, который я неправильно понимаю?

Спецификация Common Lisp определяет, что существует только четыре основанные на списке формы .Форма является допустимым фрагментом кода Lisp.

  • специальные формы (форма начинается со специального оператора)
  • макроформы (форма начинается соператор макроса)
  • формы функций (форма начинается с оператора функции)
  • формы лямбда (форма начинается с выражения лямбда)

См. Common LispHyperSpec: Представляет собой форму .

Обратите внимание, что в Common Lisp нет механизма для его расширения.Есть только эти четыре типа форм на основе списка.Можно подумать о расширениях: массивы как функции, объекты CLOS как функции, различные типы функций, такие как fexprs, переменные ... Ни один из них не поддерживается синтаксисом Common Lisp для форм на основе списков, и нет переносимого механизма для их добавления..

LAMBDA

LAMBDA имеет два разных назначения в Common Lisp:

  • это глава лямбда-выражения.
  • как макрос LAMBDA.Это расширяет (lambda ....) до (function (lambda ....))

Макрос LAMBDA был добавлен в Common Lisp после первого определения языка CLtL1 для удобства записи (lambda (x) x) вместо (function (lambda (x) x))или #'(lambda (x) x).Таким образом, это аббревиатура для формы специального оператора функции и делает код немного более простым и более похожим на схему .

0 голосов
/ 17 января 2019

Можно представить следующий перевод для оценки функции (т. Е. Машина не называет макрос или специальный оператор):

(foo arg1 arg2 ...)
~~~>
(funcall (function foo) arg1 arg2 ...)

И понимать function как специальный оператор, который переводит то, что входит в первый элемент выражения, в действительный оператор функции, который можно вызвать. Это function, который преобразует (в основном во время компиляции) лямбда-выражение в замыкание, которое может быть вызвано.

Наконец, обратите внимание, что #'foo является сокращением для (function foo).

Это не так, как на самом деле работают, на практике или в спецификации, так как (function #'(setf foo)) совершенно допустим и может вычислять функцию, которая существует, но ((setf foo) arg1 arg2 ...) не может быть допустимым вызовом функции.

Однако это объясняет, почему такое выражение, как (#'f x), недопустимо, и причина в том, что (function (function f)) не является допустимым выражением.

0 голосов
/ 16 января 2019

Взято из Практического Общего Лисп, Глава 5 :

Один из способов думать о выражениях LAMBDA - это особый вид имя функции, где само имя напрямую описывает то, что функция делает. Это объясняет, почему вы можете использовать выражение LAMBDA в место имени функции с # '.

(funcall #'(lambda (x y) (+ x y)) 2 3) ==> 5

Вы даже можете использовать выражение LAMBDA в качестве «имени» функции в выражение вызова функции. Если бы вы хотели, вы могли бы написать предыдущий FUNCALL выражение более лаконично.

((lambda (x y) (+ x y)) 2 3) ==> 5

Но это почти никогда не делается; просто стоит отметить, что это законно, чтобы подчеркнуть, что выражения LAMBDA могут быть использованы где угодно нормальное имя функции может быть.

По вашему вопросу:

Является ли LAMBDA особым исключением из жестко установленного правила, что первый элемент оцененного выражения должен быть именем некоторого операция, или есть более последовательный набор правил, который я недоразумение?

Технически нет , поскольку лямбда-выражения являются именами допустимых функций .

Редактировать : лямбда-выражения являются , а не именами функций, но вы можете думать о них как об именах функций, где «само имя напрямую описывает действия функции».

Также см. Почему # используется перед лямбда-выражением в Common Lisp?

Причина (#'f 12) не работает, потому что

  • вы сохранили функцию в ячейке значения символа f, а
  • читатель ожидает символ со значением в его функциональной ячейке, которое #'f не равно
...