Spec-Zone.ru › Elisp

Встроенные функции

Встроенная функция — это функция, которая работает так же, как и обычная функция, за исключением одного момента: при байткодировании вызова функции (см. Байткодирование) определение функции расширяется в вызывающей программе.

Простой способ определить встроенную функцию — это написать defsubst вместо defun. Остальная часть определения выглядит точно так же, но использование defsubst указывает на то, что она должна быть встроенной при байткодировании.

Макрос: defsubst name args [doc] [declare] [interactive] body…

Этот макрос определяет встроенную функцию. Его синтаксис точно такой же, как и у defun (см. Определение функций).

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

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

Кроме того, встроенные функции плохо работают с отладкой, трассировкой и консультированием (см. Консультирование функций). Поскольку простота отладки и гибкость переопределения функций являются важными особенностями Emacs, не следует преобразовывать функцию во встроенную, даже если она небольшая, если её скорость не является действительно критически важной, и вы не пробовали её время, чтобы убедиться, что использование defun не вызывает проблем с производительностью.

После определения встроенной функции её встроенное расширение может быть выполнено позже в том же файле, как и для макросов.

Можно использовать defmacro для определения макроса, который расширяется в тот же код, что и встроенная функция (см. Макросы). Но этот макрос будет ограничен непосредственным использованием в выражениях — макрос нельзя вызывать с apply, mapcar и так далее. Кроме того, потребуется работа для преобразования обычной функции в макрос. Преобразование в встроенную функцию легко; просто замените defun на defsubst. Поскольку каждый аргумент встроенной функции вычисляется ровно один раз, вам не нужно беспокоиться о том, сколько раз тело использует аргументы, как в случае с макросами.

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

Макрос: define-inline name args [doc] [declare] body…

Определите функцию name, предоставив код, который выполнит её инлайнинг, как макрос компилятора. Функция будет принимать список аргументов args и будет иметь указанное body.

Если присутствует doc, это должна быть строка документации функции (см. Документация функций); declare, если присутствует, должен быть формой declare (см. Форма declare), определяющей метаданные функции.

Функции, определенные с помощью define-inline, имеют несколько преимуществ по сравнению с макросами, определенными с помощью defsubst или defmacro:

  • - Их можно передавать в mapcar (см. Функции отображения).
  • - Они более эффективны.
  • - Они могут использоваться как формы-позиции для хранения значений (см. Обобщенные переменные).
  • - Они ведут себя более предсказуемо, чем cl-defsubst (см. Списки аргументов в Расширения Common Lisp для GNU Emacs Lisp).

Как и defmacro, функция, встроенная с помощью define-inline, наследует правила области видимости, динамические или лексические, из места вызова. См. Область видимости переменных.

Следующие макросы должны использоваться в теле функции, определенной с помощью define-inline.

Макрос: inline-quote expression

Вывести expression для define-inline. Это аналогично обратной кавычке (см. Обратная кавычка), но цитирует код и принимает только ,, а не ,@.

Макрос: inline-letevals (bindings…) body…

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

Это аналогично let (см. Локальные переменные): устанавливает локальные переменные, как указано в bindings, и затем вычисляет body с этими связываниями в силе.

Каждый элемент bindings должен быть либо символом, либо списком вида (var expr); результатом является вычисление expr и привязка var к результату. Однако, когда элемент bindings — это просто символ var, результат вычисления var перепривязывается к var (что довольно отличается от того, как работает let).

Хвост bindings может быть либо nil, либо символом, который должен содержать список аргументов, в этом случае каждый аргумент вычисляется, а символ привязывается к результирующему списку.

Макрос: inline-const-p expression

Возвращает не-nil, если значение expression уже известно.

Макрос: inline-const-val expression

Возвращает значение expression.

Макрос: inline-error format &rest args

Вызвать ошибку, отформатировав args в соответствии с format.

Вот пример использования define-inline:

(define-inline myaccessor (obj)
  (inline-letevals (obj)
    (inline-quote (if (foo-p ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))))

Это эквивалентно

(defsubst myaccessor (obj)
  (if (foo-p obj) (aref (cdr obj) 3) (aref obj 2)))

Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Inline-Functions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API