Сам интерпретатор Emacs Lisp не выполняет проверку типов фактических аргументов, передаваемых функциям при их вызове. Он не может этого делать, поскольку аргументы функций в Lisp не имеют объявленных типов данных, в отличие от других языков программирования. Поэтому каждая отдельная функция должна сама проверять, принадлежит ли каждый фактический аргумент типу, который функция может использовать.
Все встроенные функции проверяют типы своих фактических аргументов, когда это уместно, и выдают ошибку wrong-type-argument, если аргумент имеет неверный тип. Например, вот что происходит, если передать аргумент функции +, который она не может обработать:
(+ 2 'a)
error→ Wrong type argument: number-or-marker-p, a
Если вы хотите, чтобы ваша программа обрабатывала разные типы по-разному, вы должны выполнять явную проверку типов. Самый распространённый способ проверить тип объекта — вызвать функцию предикат типа. В Emacs есть предикат типа для каждого типа, а также некоторые предикаты для комбинаций типов.
Функция-предикат типа принимает один аргумент; она возвращает t, если аргумент принадлежит соответствующему типу, и nil в противном случае. Следуя общему соглашению Lisp для функций-предикатов, имена большинства предикатов типов заканчиваются на «p».
Вот пример, в котором используются предикаты listp для проверки на список и symbolp для проверки на символ.
(defun add-on (x)
(cond ((symbolp x)
;; Если X — символ, поместить его в LIST.
(setq list (cons x list)))
((listp x)
;; Если X — список, добавить его элементы в LIST.
(setq list (append x list)))
(t
;; Мы обрабатываем только символы и списки.
(error "Invalid argument %s in add-on" x))))
Ниже приведена таблица предопределённых предикатов типов в алфавитном порядке со ссылками на дополнительную информацию.
atomСм. atom.
arraypСм. arrayp.
bignumpСм. bignump.
bool-vector-pСм. bool-vector-p.
booleanpСм. booleanp.
bufferpСм. bufferp.
byte-code-function-pСм. byte-code-function-p.
case-table-pСм. case-table-p.
char-or-string-pСм. char-or-string-p.
char-table-pСм. char-table-p.
closurepСм. closurep.
commandpСм. commandp.
compiled-function-pСм. compiled-function-p.
condition-variable-pСм. condition-variable-p.
conspСм. consp.
custom-variable-pСм. custom-variable-p.
fixnumpСм. fixnump.
floatpСм. floatp.
fontpframe-configuration-pframe-live-pСм. frame-live-p.
framepСм. framep.
functionpСм. functionp.
hash-table-pСм. hash-table-p.
integer-or-marker-pСм. integer-or-marker-p.
integerpСм. integerp.
interpreted-function-pkeymappСм. keymapp.
keywordplistpСм. listp.
markerpСм. markerp.
mutexpСм. mutexp.
nlistpСм. nlistp.
number-or-marker-pСм. number-or-marker-p.
numberpСм. numberp.
obarraypСм. obarrayp.
overlaypСм. overlayp.
processpСм. processp.
recordpСм. recordp.
sequencepСм. sequencep.
string-or-null-pСм. string-or-null-p.
stringpСм. stringp.
subrpСм. subrp.
symbolpСм. symbolp.
syntax-table-pСм. syntax-table-p.
threadpСм. threadp.
vectorpСм. vectorp.
wholenumpСм. wholenump.
window-configuration-pwindow-live-pСм. window-live-p.
windowpСм. windowp.
Наиболее общий способ проверить тип объекта — вызвать функцию type-of. Напомним, что каждый объект принадлежит одному и только одному примитивному типу; type-of сообщает, какому именно (см. Типы данных Lisp). Но type-of ничего не знает о непримитивных типах. В большинстве случаев предпочтительнее использовать предикаты типов, а не type-of.
Эта функция возвращает символ, именующий примитивный тип object. Возвращаемое значение — один из символов bool-vector, buffer, char-table, compiled-function, condition-variable, cons, finalizer, float, font-entity, font-object, font-spec, frame, hash-table, integer, marker, mutex, obarray, overlay, process, string, subr, symbol, thread, vector, window или window-configuration. Однако если object является записью (record), возвращается тип, заданный её первым полем; см. Записи.
(type-of 1)
⇒ integer
(type-of 'nil)
⇒ symbol
(type-of '()) ; () — это nil.
⇒ symbol
(type-of '(x))
⇒ cons
(type-of (record 'foo))
⇒ foo
Эта функция возвращает символ, именующий тип object. Обычно она ведёт себя как type-of, за исключением того, что гарантирует возврат наиболее точного возможного типа, что также означает, что конкретный возвращаемый тип может меняться в зависимости от версии Emacs. По этой причине, как правило, никогда не следует сравнивать её возвращаемое значение с каким-либо фиксированным набором типов.
(cl-type-of 1)
⇒ fixnum
(cl-type-of 'nil)
⇒ null
(cl-type-of (record 'foo))
⇒ foo