13.4 Определение функций

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

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

defun — это обычный способ определения новых функций Lisp. Он определяет символ name как функцию со списком аргументов args (см. Особенности списков аргументов) и формами тела, заданными body. Ни name, ни args не должны заключаться в кавычки.

doc, если присутствует, должна быть строкой, задающей строку документации функции (см. Строки документации функций). declare, если присутствует, должна быть формой declare, задающей метаданные функции (см. Форма declare). interactive, если присутствует, должна быть формой interactive, задающей способ интерактивного вызова функции (см. Интерактивный вызов).

Возвращаемое значение defun не определено.

Вот несколько примеров:

(defun foo () 5)
(foo)
     ⇒ 5

(defun bar (a &optional b &rest c)
    (list a b c))
(bar 1 2 3 4 5)
     ⇒ (1 2 (3 4 5))
(bar 1)
     ⇒ (1 nil nil)
(bar)
error→ Неправильное количество аргументов.

(defun capitalize-backwards ()
  "Сделать заглавной последнюю букву слова под точкой."
  (interactive)
  (backward-word 1)
  (forward-word 1)
  (backward-char 1)
  (capitalize-word 1))

Большинство функций Emacs являются частью исходного кода программ на Lisp и определяются, когда считыватель Emacs Lisp читает исходный код программы перед её выполнением. Однако вы также можете определять функции динамически во время выполнения, например, генерируя вызовы defun во время выполнения кода вашей программы. Если вы делаете это, имейте в виду, что справочные команды Emacs, такие как C-h f, которые отображают в буфере *Help* кнопку для перехода к определению функции, могут не найти исходный код, поскольку динамическое создание функции обычно выглядит совсем не так, как обычные статические вызовы defun. Вы можете облегчить задачу поиска кода, который генерирует такие функции, используя свойство definition-name (см. Стандартные свойства символов).

Будьте осторожны, чтобы случайно не переопределить существующие функции. defun переопределяет даже примитивные функции, такие как car, без каких-либо колебаний или предупреждений. Emacs не препятствует вам в этом, потому что переопределение функции иногда делается намеренно, и нет способа отличить намеренное переопределение от случайного.

Функция: defalias name definition &optional doc

Эта функция определяет символ name как функцию с определением definition. definition может быть любой допустимой функцией или макросом Lisp, специальной формой (см. Специальные формы), клавиатурной картой (см. Клавиатурные карты) или вектором/строкой (клавиатурный макрос). Возвращаемое значение defalias не определено.

Если doc не равна nil, она становится строкой документации функции для name. В противном случае используется документация, предоставленная definition.

Внутри defalias обычно использует fset для установки определения. Однако если name имеет свойство defalias-fset-function, то связанное с ним значение используется как функция, вызываемая вместо fset.

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

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

Если результирующая цепочка определений функций оказалась бы циклической, Emacs выдаст ошибку cyclic-function-indirection.

Функция: function-alias-p object

Проверяет, является ли object псевдонимом функции. Если является, возвращает список символов, представляющих цепочку псевдонимов функции, в противном случае — nil. Например, если a — это псевдоним для b, а b — псевдоним для c:

(function-alias-p 'a)
    ⇒ (b c)

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

Вы не можете создать новую примитивную функцию с помощью defun или defalias, но вы можете использовать их для изменения определения функции любого символа, даже такого, как car или x-popup-menu, чьё обычное определение является примитивом. Однако это рискованно: например, практически невозможно переопределить car, не нарушив при этом полностью работу Lisp. Переопределение малоизвестной функции, такой как x-popup-menu, менее опасно, но всё равно может работать не так, как вы ожидаете. Если существуют вызовы примитива из кода на C, они вызывают непосредственно C-определение примитива, поэтому изменение определения символа не повлияет на них.

См. также defsubst, который определяет функцию подобно defun и сообщает компилятору Lisp о необходимости выполнять её подстановку в коде (инлайн-развёртывание). См. Подставляемые (инлайн) функции.

Чтобы отменить определение имени функции, используйте fmakunbound. См. Доступ к содержимому ячеек функций.