Байт-скомпилированные функции используют специальный тип данных: они являются замыканиями. Замыкания используются как для байт-скомпилированных функций Lisp, так и для интерпретируемых функций Lisp. Всякий раз, когда такой объект появляется как функция для вызова, Emacs использует соответствующий интерпретатор для выполнения либо байт-кода, либо нескомпилированного кода Lisp.
Внутренне замыкание очень похоже на вектор; его
элементы можно получить с помощью aref. Его печатное
представление похоже на представление вектора, с дополнительным знаком ‘#’
перед открывающейся скобкой ‘[’. Оно должно иметь как минимум три элемента;
максимального числа нет, но только первые шесть элементов имеют какое-либо
нормальное использование. Они следующие:
Описание аргументов. Это может быть либо список
аргументов, как описано в О возможностях списков аргументов, либо целое число,
кодирующее требуемое количество аргументов. В последнем случае значение
описателя указывает минимальное количество аргументов в битах с нуля по 6, а максимальное количество аргументов в битах с 8 по 14. Если
список аргументов использует &rest, то бит 7 установлен; в противном случае он сброшен.
Когда замыкание является байт-скомпилированной функцией, если argdesc является списком, аргументы будут динамически привязаны перед выполнением байт-кода. Если argdesc является целым числом, аргументы вместо этого будут помещены в стек интерпретатора байт-кода перед выполнением кода.
Для интерпретируемых функций этот элемент — это (непустой) список форм Lisp, составляющих тело функции. Для байт-скомпилированных функций это строка, содержащая инструкции байт-кода.
Для байт-скомпилированных функций здесь хранится вектор объектов Lisp,
на которые ссылается байт-код. К ним относятся символы, используемые в качестве
имен функций и имен переменных.
Для интерпретируемых функций это nil, если функция использует старый
диалект Emacs Lisp с динамической областью видимости, и в противном случае здесь хранится
лексическая среда функции.
Максимальный размер стека, который требуется этой функции. Этот элемент остается неиспользованным для интерпретируемых функций.
Строка документации (если есть); в противном случае nil. Значение может
быть числом или списком, если строка документации хранится в файле. Используйте функцию documentation,
чтобы получить фактическую строку документации (см. Доступ к строкам документации).
Интерактивная спецификация (если есть). Это может быть строка или выражение Lisp.
Это nil для функции, которая не является интерактивной.
Вот пример объекта байт-кода в печатном представлении. Это определение команды
backward-sexp.
#[256 "\211\204^G^@\300\262^A\301^A[!\207" [1 forward-sexp] 3 1793299 "^p"]
Примитивный способ создания объекта байт-кода — это использование
make-byte-code:
Эта функция конструирует и возвращает замыкание, представляющее объект функции байт-кода с elements в качестве его элементов.
Вы не должны пытаться самостоятельно определить элементы для функции байт-кода, потому что если они будут несогласованными, Emacs может завершиться при вызове функции. Всегда оставляйте это байт-компилятору; он обеспечивает согласованность элементов (мы надеемся).
Примитивный способ создания интерпретируемой функции — это использование
make-interpreted-closure:
Эта функция конструирует и возвращает замыкание, представляющее
интерпретируемую функцию с аргументами args и чьим телом является
body, которое должно быть не-nil списком форм Lisp. env — это
лексическая среда в том же формате, что и используется с eval
(см. Eval). Документация docstring, если она не-nil, должна быть
строкой, а интерактивная форма iform, если она не-nil, должна иметь вид
(interactive arg-descriptor) (см. Использование interactive).