6.2 Предикаты типов данных

Возможно наиболее важными предикатами в Lisp’е это предикаты, которые различают типы данных. То есть позволяют узнать принадлежит ли заданный объект данному типу. Также предикаты могут сравнивать два спецификатора типов.

6.2.1 Основные предикаты

Если тип данных рассматривать, как множество все объектов, принадлежащих этому типу, тогда функция typep проверяет принадлежность множеству, тогда как subtypep — принадлежность подмножеству.

[Функция] typep object type

typep является предикатом, который истинен, если объект object принадлежит типу type, и ложен в противном случае. Следует отметить, что объект может принадлежать нескольким типам, так как один тип может включать другой. type может быть любым спецификатором типа, описанным в главе 4, за исключением того, что он не может быть или включать список спецификатор типа, у которого первый элемент равен function или values. Спецификатор формы (satisfies fn) обрабатывается просто как применение функции fn к объекту object (смотрите funcall). Объект object принадлежит заданному типу, если результат не равен nil.

X3J13 voted in January 1989 to change typep to give specialized array and complex type specifiers the same meaning for purposes of type discrimination as they have for declaration purposes. Of course, this also applies to such type specifiers as vector and simple-array (see section 4.5). Thus

(typep foo ’(array bignum))

in the first edition asked the question, Is foo an array specialized to hold bignums? but under the new interpretation asks the question, Could the array foo have resulted from giving bignum as the :element-type argument to make-array?


[Функция] subtypep type1 type2

Аргументы должны быть спецификаторами типов, но только теми, которые могут использоваться и для typep. Два спецификатора типа сравниваются. Данный предикат истинен, если тип type1 точно является подтипом типа type2, иначе предикат ложен. Если результат nil, тогда тип type1 может быть, а может и не быть подтипом типа type2 (иногда это невозможно определить, особенно когда используется тип satisfies). Второе возвращаемое значение указывает на точность результата. Если оно является истиной, значит первое значение указывает на точную принадлежность типов. Таким образом возможны следующие комбинации результатов:

t t type1 точно является подтипом type2
nil t type1 точно не является подтипом type2
nil nil subtypep не может определить отношение

X3J13 voted in January 1989 to place certain requirements upon the implementation of subtypep, for it noted that implementations in many cases simply “give up” and return the two values nil and nil when in fact it would have been possible to determine the relationship between the given types. The requirements are as follows, where it is understood that a type specifier s involves a type specifier u if either s contains an occurrence of u directly or s contains a type specifier w defined by deftype whose expansion involves u.

In addition, X3J13 voted to clarify that in some cases the relationships between types as reflected by subtypep may be implementation-specific. For example, in an implementation supporting only one type of floating-point number, (subtypep ’float ’long-float) would return t and t, since the two types would be identical.

Note that satisfies is an exception because relationships between types involving satisfies are undecidable in general, but (as X3J13 noted) and, or, not, and member are merely very messy to deal with. In all likelihood these will not be addressed unless and until someone is willing to write a careful specification that covers all the cases for the processing of these type specifiers by subtypep. The requirements stated above were easy to state and probably suffice for most cases of interest.

X3J13 voted in January 1989 to change subtypep to give specialized array and complex type specifiers the same meaning for purposes of type discrimination as they have for declaration purposes. Of course, this also applies to such type specifiers as vector and simple-array (see section 4.5).

If A and B are type specifiers (other than *, which technically is not a type specifier anyway), then (array A) and (array B) represent the same type in a given implementation if and only if they denote arrays of the same specialized representation in that implementation; otherwise they are disjoint. To put it another way, they represent the same type if and only if (upgraded-array-element-type ’A) and (upgraded-array-element-type ’B) are the same type. Therefore

(subtypep ’(array A) ’(array B))

is true if and only if (upgraded-array-element-type ’A) is the same type as (upgraded-array-element-type ’B).

The complex type specifier is treated in a similar but subtly different manner. If A and B are two type specifiers (but not *, which technically is not a type specifier anyway), then (complex A) and (complex B) represent the same type in a given implementation if and only if they refer to complex numbers of the same specialized representation in that implementation; otherwise they are disjoint. Note, however, that there is no function called make-complex that allows one to specify a particular element type (then to be upgraded); instead, one must describe specialized complex numbers in terms of the actual types of the parts from which they were constructed. There is no number of type (or rather, representation) float as such; there are only numbers of type single-float, numbers of type double-float, and so on. Therefore we want (complex single-float) to be a subtype of (complex float).

The rule, then, is that (complex A) and (complex B) represent the same type (and otherwise are disjoint) in a given implementation if and only if either the type A is a subtype of B, or (upgraded-complex-part-type ’A) and (upgraded-complex-part-type ’B) are the same type. In the latter case (complex A) and (complex B) in fact refer to the same specialized representation. Therefore

(subtypep ’(complex A) ’(complex B))

is true if and only if the results of (upgraded-complex-part-type ’A) and (upgraded-complex-part-type ’B) are the same type.

Under this interpretation

(subtypep ’(complex single-float) ’(complex float))

must be true in all implementations; but

(subtypep ’(array single-float) ’(array float))

is true only in implementations that do not have a specialized array representation for single-float elements distinct from that for float elements in general.


6.2.2 Специальные предикаты

Следующие предикаты осуществляют проверку определённых типов данных.

[Функция] null object

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

(null x)  (typep x ’null)  (eq x ’())


[Функция] symbolp object

symbolp истинен, если её аргумент является символом, в противном случае ложен.

(symbolp x)  (typep x ’symbol)


[Функция] atom object

Предикат atom истинен, если аргумент не является cons-ячейкой, в противном случае ложен. Следует отметить (atom ’()) являет истиной, потому что ()nil.

(atom x)  (typep x ’atom)  (not (typep x ’cons))


[Функция] consp object

Предикат consp истинен, если его аргумент является cons-ячейкой, в противном случае ложен. Следует отметить, пустой список не является cons-ячейкой, так (consp ’())  (consp ’nil)  nil.

(consp x)  (typep x ’cons)  (not (typep x ’atom))


[Функция] listp object

listp истинен, если его аргумент является cons-ячейкой или пустым списком (), в противном случае ложен. Она не проверяет является ли «список Ъ (true list)» (завершающийся nil) или «с точкой (dotted)» (завершающийся не-null атомом).

(listp x)  (typep x ’list)  (typep x ’(or cons null))


[Функция] numberp object

numberp истинен, если аргумент это любой вид числа, в противном случае ложен.

(numberp x)  (typep x ’number)


[Функция] integerp object

integerp истинен, если аргумент целое число, в противном случае ложен.

(integerp x)  (typep x ’integer)


[Функция] rationalp object

rationalp истинен, если аргумент рациональное число (дробь или целое), в противном случае ложен.

(rationalp x)  (typep x ’rational)


[Функция] floatp object

floatp истинен, если аргумент число с плавающей точкой, в противном случае ложен.

(floatp x)  (typep x ’float)


[Функция] realp object

realp истинна, если аргумент является действительным числом, иначе ложна.

(realp x)  (typep x ’real)


[Функция] complexp object

complexp истинен, если аргумент комплексное число, в противном случае ложен.

(complexp x)  (typep x ’complex)


[Функция] characterp object

characterp истинен, если аргумент – буква, иначе ложен.

(characterp x)  (typep x ’character)


[Функция] stringp object

stringp истинен, если аргумент строка, иначе ложен.

(stringp x)  (typep x ’string)


[Функция] bit-vector-p object

bit-vector-p истинен, если аргумент битовый вектор, иначе ложен.

(bit-vector-p x)  (typep x ’bit-vector)


[Функция] vectorp object

vectorp истинен, если аргумент вектор, иначе ложен.

(vectorp x)  (typep x ’vector)


[Функция] simple-vector-p object

vectorp истинен, если аргумент простой общий вектор, иначе ложен.

(simple-vector-p x)  (typep x ’simple-vector)


[Функция] simple-string-p object

simple-string-p истинен, если аргумент простая строка, иначе ложен.

(simple-string-p x)  (typep x ’simple-string)


[Функция] simple-bit-vector-p object

simple-bit-vector-p истинен, если аргумент простой битовый вектор, иначе ложен.

(simple-bit-vector-p x)  (typep x ’simple-bit-vector)


[Функция] arrayp object

arrayp истинен, если аргумент массив, иначе ложен.

(arrayp x)  (typep x ’array)


[Функция] packagep object

packagep истинен, если аргумент является пакетом, иначе является ложью.

(packagep x)  (typep x ’package)


[Функция] functionp object

(functionp x)  (typep x ’function)

Типы cons и symbol непересекаются с типом function. functionp является ложной для символов и списков.


[Функция] compiled-function-p object

compiled-function-p истинен, если аргумент — скомпилированный объект кода, иначе ложен.

(compiled-function-p x)  (typep x ’compiled-function)


Смотрите также standard-char-p, string-char-p, streamp, random-state-p, readtablep, hash-table-p и pathnamep.