setfВ этом разделе описывается, как определить новые формы, над которыми setf может работать.
Этот макрос позволяет легко определять методы setf для простых случаев. name — это имя функции, макроса или специальной формы. Вы можете использовать этот макрос всякий раз, когда name имеет соответствующую функцию setter, которая обновляет его, например, (gv-define-simple-setter car setcar).
Этот макрос преобразует вызов вида
(setf (name args…) value)
в
(setter args… value)
Такой вызов setf документирован как возвращающий value. Это не проблема, например, с car и setcar, потому что setcar возвращает установленное значение. Если ваша функция setter не возвращает value, используйте не-nil значение для аргумента fix-return в gv-define-simple-setter. Это расширяется до чего-то эквивалентного
(let ((temp value)) (setter args… temp) temp)
тем самым гарантируя, что он возвращает правильный результат.
Этот макрос позволяет выполнять более сложные расширения setf, чем предыдущая форма. Возможно, вам потребуется использовать эту форму, например, если нет простой функции
Этот макрос расширяет форму
(setf (name args…) value) путем
сначала привязки форм аргументов setf
(value args…) в соответствии с arglist,
а затем выполнения body. body должен вернуть форму Lisp,
которая выполняет присваивание, и, наконец, возвращает установленное значение. Пример использования этого макроса:
(gv-define-setter caar (val x) `(setcar (car ,x) ,val))
Для большего контроля над расширением можно использовать макрос gv-define-expander. Например, таким образом можно реализовать изменяемую substring:
(gv-define-expander substring
(lambda (do place from &optional to)
(gv-letplace (getter setter) place
(macroexp-let2* (from to)
(funcall do `(substring ,getter ,from ,to)
(lambda (v)
(macroexp-let2* (v)
`(progn
,(funcall setter `(cl--set-substring
,getter ,from ,to ,v))
,v))))))))
Макрос gv-letplace может быть полезен при определении макросов, которые выполняют действия, аналогичные setf; например, макрос incf из Common Lisp можно реализовать таким образом:
(defmacro incf (place &optional n)
(gv-letplace (getter setter) place
(macroexp-let2* ((v (or n 1)))
(funcall setter `(+ ,v ,getter)))))
getter будет привязан к копируемому выражению, которое возвращает значение place. setter будет привязан к функции, которая принимает выражение v и возвращает новое выражение, устанавливающее place в v. body должен возвращать выражение Emacs Lisp, манипулирующее place через getter и setter.
Подробности см. в исходном файле gv.el.
Эта функция заставляет компилятор байт предупредить о том, что обобщенная переменная obsolete-name устарела. Если current-name — это символ, то сообщение предупреждения гласит использовать current-name вместо obsolete-name. Если current-name — это строка, то это сообщение. when должен быть строкой, указывающей, когда переменная была впервые объявлена устаревшей (обычно строка с номером версии).
Примечание Common Lisp: Common Lisp определяет другой способ указания поведения
setfфункции, а именно функцииsetf, имена которых являются списками(setf name)вместо символов. Например,(defun (setf foo) …)определяет функцию, которая используется, когдаsetfприменяется кfoo. Emacs не поддерживает это. Использованиеsetfдля формы, для которой не было определено соответствующее расширение, является ошибкой во время компиляции. В Common Lisp это не ошибка, поскольку функция(setf func)может быть определена позже.