13.7 Анонимные функции

Хотя функции обычно определяются с помощью defun и одновременно получают имена, иногда удобно использовать явное выражение lambda — анонимную функцию. Анонимные функции допустимы везде, где допустимы имена функций. Их часто присваивают переменным или передают в качестве аргументов функциям; например, вы можете передать одну в качестве аргумента function функции mapcar, которая применяет эту функцию к каждому элементу списка (см. Функции отображения). Для реалистичного примера см. describe-symbols example.

При определении выражения lambda, которое будет использоваться как анонимная функция, следует использовать макрос lambda, специальную форму function или синтаксис чтения #':

Макрос: lambda args [doc] [interactive] body…

Этот макрос возвращает анонимную функцию со списком аргументов args, строкой документации doc (если есть), спецификацией интерактивности interactive (если есть) и телами, заданными body.

Например, этот макрос делает формы lambda почти самоцитируемыми: вычисление формы, чей CAR — это lambda, дает значение, которое почти идентично самой форме:

(lambda (x) (* x x))
     ⇒ #f(lambda (x) :dynbind (* x x))

При вычислении с лексическим связыванием результатом является аналогичный объект замыкания, где маркер :dynbind заменяется захваченными переменными (см. Замыкания).

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

Специальная форма: function function-object

Эта специальная форма возвращает значение функции function-object. Во многих отношениях она похожа на quote (см. Цитирование). Но в отличие от quote, она также служит указанием для исполнителя Emacs и компилятора байт-кода о том, что function-object предназначена для использования в качестве функции. Предполагая, что function-object является допустимым выражением lambda, это имеет два эффекта:

  • При компиляции байт-кода function-object компилируется в объект функции байт-кода (см. Компиляция байт-кода).
  • При включенном лексическом связывании function-object преобразуется в замыкание. См. Замыкания.

Когда function-object является символом, а код компилируется в байт-код, компилятор байт-кода выдаст предупреждение, если эта функция не определена или может быть неизвестна во время выполнения.

Синтаксис чтения #' — это сокращение для использования function. Следующие формы эквивалентны:

(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))

В следующем примере мы определяем функцию change-property, которая принимает функцию в качестве третьего аргумента, за которой следует функция double-property, которая использует change-property, передавая ей анонимную функцию:

(defun change-property (symbol prop function)
  (let ((value (get symbol prop)))
    (put symbol prop (funcall function value))))

(defun double-property (symbol prop)
  (change-property symbol prop (lambda (x) (* 2 x))))

Обратите внимание, что мы не цитируем форму lambda.

Если вы скомпилируете приведенный выше код, анонимная функция также будет скомпилирована. Это не произойдет, если, например, вы сконструировали анонимную функцию, цитируя ее как список:

(defun double-property (symbol prop)
  (change-property symbol prop '(lambda (x) (* 2 x))))

В этом случае анонимная функция остается в виде выражения lambda в скомпилированном коде. Компилятор байт-кода не может предположить, что этот список является функцией, даже если он выглядит как таковой, поскольку он не знает, что change-property намеревается использовать его как функцию.