17.6 Объекты функций замыканий

Байт-скомпилированные функции используют специальный тип данных: они являются замыканиями. Замыкания используются как для байт-скомпилированных функций Lisp, так и для интерпретируемых функций Lisp. Всякий раз, когда такой объект появляется как функция для вызова, Emacs использует соответствующий интерпретатор для выполнения либо байт-кода, либо нескомпилированного кода Lisp.

Внутренне замыкание очень похоже на вектор; его элементы можно получить с помощью aref. Его печатное представление похоже на представление вектора, с дополнительным знаком ‘#’ перед открывающейся скобкой ‘[’. Оно должно иметь как минимум три элемента; максимального числа нет, но только первые шесть элементов имеют какое-либо нормальное использование. Они следующие:

argdesc

Описание аргументов. Это может быть либо список аргументов, как описано в О возможностях списков аргументов, либо целое число, кодирующее требуемое количество аргументов. В последнем случае значение описателя указывает минимальное количество аргументов в битах с нуля по 6, а максимальное количество аргументов в битах с 8 по 14. Если список аргументов использует &rest, то бит 7 установлен; в противном случае он сброшен.

Когда замыкание является байт-скомпилированной функцией, если argdesc является списком, аргументы будут динамически привязаны перед выполнением байт-кода. Если argdesc является целым числом, аргументы вместо этого будут помещены в стек интерпретатора байт-кода перед выполнением кода.

code

Для интерпретируемых функций этот элемент — это (непустой) список форм Lisp, составляющих тело функции. Для байт-скомпилированных функций это строка, содержащая инструкции байт-кода.

constants

Для байт-скомпилированных функций здесь хранится вектор объектов Lisp, на которые ссылается байт-код. К ним относятся символы, используемые в качестве имен функций и имен переменных. Для интерпретируемых функций это nil, если функция использует старый диалект Emacs Lisp с динамической областью видимости, и в противном случае здесь хранится лексическая среда функции.

stacksize

Максимальный размер стека, который требуется этой функции. Этот элемент остается неиспользованным для интерпретируемых функций.

docstring

Строка документации (если есть); в противном случае nil. Значение может быть числом или списком, если строка документации хранится в файле. Используйте функцию documentation, чтобы получить фактическую строку документации (см. Доступ к строкам документации).

interactive

Интерактивная спецификация (если есть). Это может быть строка или выражение Lisp. Это nil для функции, которая не является интерактивной.

Вот пример объекта байт-кода в печатном представлении. Это определение команды backward-sexp.

#[256
  "\211\204^G^@\300\262^A\301^A[!\207"
  [1 forward-sexp]
  3
  1793299
  "^p"]

Примитивный способ создания объекта байт-кода — это использование make-byte-code:

Функция: make-byte-code &rest elements

Эта функция конструирует и возвращает замыкание, представляющее объект функции байт-кода с elements в качестве его элементов.

Вы не должны пытаться самостоятельно определить элементы для функции байт-кода, потому что если они будут несогласованными, Emacs может завершиться при вызове функции. Всегда оставляйте это байт-компилятору; он обеспечивает согласованность элементов (мы надеемся).

Примитивный способ создания интерпретируемой функции — это использование make-interpreted-closure:

Функция: make-interpreted-closure args body env &optional docstring iform

Эта функция конструирует и возвращает замыкание, представляющее интерпретируемую функцию с аргументами args и чьим телом является body, которое должно быть не-nil списком форм Lisp. env — это лексическая среда в том же формате, что и используется с eval (см. Eval). Документация docstring, если она не-nil, должна быть строкой, а интерактивная форма iform, если она не-nil, должна иметь вид (interactive arg-descriptor) (см. Использование interactive).