10.2.4 Косвенная адресация символов функций

Если первый элемент списка является символом, то при вычислении исследуется функциональная ячейка этого символа, и вместо исходного символа используется её содержимое. Если содержимым является другой символ, этот процесс, называемый косвенной адресацией символов функций, повторяется до тех пор, пока не будет получен не-символ. См. Именование функции для получения дополнительной информации о косвенной адресации символов функций. В конечном итоге мы получаем не-символ, который должен быть функцией или другим подходящим объектом.

Более точно, теперь мы должны иметь Lisp-функцию (лямбда-выражение), байт-кодовую функцию, примитивную функцию, Lisp-макрос, специальную форму или объект автозагрузки. Каждый из этих типов описывается в одном из следующих разделов. Если объект не принадлежит ни одному из этих типов, Emacs сигнализирует об ошибке invalid-function.

Следующий пример иллюстрирует процесс косвенной адресации символов. Мы используем fset для установки функциональной ячейки символа и symbol-function для получения содержимого функциональной ячейки (см. Доступ к содержимому функциональной ячейки). В частности, мы сохраняем символ car в функциональную ячейку first, а символ first — в функциональную ячейку erste.

;; Построим эту цепочку функциональных ячеек:
;;   -------------       -----        -------        -------
;;  | #<subr car> | <-- | car |  <-- | first |  <-- | erste |
;;   -------------       -----        -------        -------
(symbol-function 'car)
     ⇒ #<subr car>
(fset 'first 'car)
     ⇒ car
(fset 'erste 'first)
     ⇒ first
(erste '(1 2 3))   ; Вызов функции, на которую ссылается erste.
     ⇒ 1

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

((lambda (arg) (erste arg))
 '(1 2 3))
     ⇒ 1

Выполнение самой функции вычисляет её тело; это включает косвенную адресацию символов при вызове erste.

Эта форма используется редко и в настоящее время устарела. Вместо неё следует писать:

(funcall (lambda (arg) (erste arg))
         '(1 2 3))

или просто

(let ((arg '(1 2 3))) (erste arg))

Встроенная функция indirect-function предоставляет простой способ явного выполнения косвенной адресации символов функций.

Функция: indirect-function function

Эта функция возвращает значение function как функции. Если function является символом, то она находит определение функции function и повторяет процесс с этим значением. Если function не является символом, то она возвращает сам function.

Эта функция возвращает nil, если конечный символ не привязан.

Существует также второй необязательный аргумент, который устарел и не оказывает никакого эффекта.

Вот как можно было бы определить indirect-function на Lisp:

(defun indirect-function (function)
  (if (and function
           (symbolp function))
      (indirect-function (symbol-function function))
    function))