4. TYPE SPECIFIERS
This chapter contains the following sections:
4.1 Type Specifier Symbols
4.2 Type Specifier Lists
In Common LISP, types are named by symbols or lists. These are called type specifiers. Symbols name built-in classes of objects, for example integer list sequence, bit-vector. Lists are used to specify combinations or specializations of types. Some type specifiers are only found in type specifier lists at the head of those lists. (The term type specifier is used interchangeably for the type specifier lists and the symbols found at their head).
NOTE: The implementation supports the ANSI version of the Common LISP type hierarchy. The following types, defined in CLTL1 have been removed from the implementation: common, string-char. The following type specifiers have been added to the implemenation per CLTL2 and ANSI: base-character, extended-character, eql and real.
4.1 Type Specifier Symbols
A type specifier is a symbol which names a type, either predefined or created by the programmer using defstruct or defclass. The built-in type specifiers supported by Star Sapphire Common LISP are shown in the following table.
Symbols which represent types which are generated internally by this implementation are checked off in the 'implementation' column. Note that ALL of the types specifiers listed below with a * ARE supported; the ones in the implementation column are the basic types which are generated by Star Sapphire internally. For instance, you can generate a cons using the cons function;
(setq x (cons 1 2)) => (1 . 2)
(consp x) => t
(listp x) => t
(typep x 'cons) => t
(typep x 'list) => t
However, internally the object you have assigned to x has the type cons (represented by a bit pattern stamped in its virtual address). Another example is the type number. Star Sapphire will never produce an object of type number, however (typep 4 'number) => t.
Those checked off in the Symbol column are those which can be used as names for types. Those checked off in the List column can appear at the head of type specifier lists. Those checked off in the Impl (implementation column are actual objects, rather than an abstract type.
The X means that the usage is supported by this implementation; the * means that the usage is specified but not supported.
] |
Impl |
Symbol |
List |
and |
X |
||
array |
X |
X |
X |
atom |
X |
||
base-string |
X |
||
bignum |
X |
X |
|
bit |
X |
||
bit-vector |
X |
X |
X |
compiled-function |
X |
X |
|
complex |
X |
X |
|
cons |
X |
X |
|
double-float |
X |
X |
|
eql |
X |
||
fixnum |
X |
X |
|
Float |
X |
X |
X |
function |
X |
X |
* |
hash-table |
X |
X |
|
integer |
X |
X |
X |
keyword |
X |
||
list |
X |
||
long-float |
X |
X |
|
member |
X |
||
mod |
X |
||
nil |
X |
||
not |
X |
||
null |
X |
X |
|
number |
X |
||
or |
X |
||
package |
X |
X |
|
pathname |
X |
X |
|
random-state |
X |
X |
|
ratio |
X |
X |
|
rational |
X |
X |
|
readtable |
X |
X |
|
real |
X |
X |
|
sequence |
X |
||
short-float |
X |
X |
|
simple-base-string |
X |
||
signed-byte |
X |
X |
|
simple-array |
X |
X |
|
simple-bit-vector |
X |
X |
|
simple-string |
X |
X |
|
simple-vector |
X |
X |
|
single-float |
X |
X |
|
standard-char |
X |
||
stream |
X |
X |
|
string |
X |
X |
X |
symbol |
X |
X |
|
t |
X |
||
unsigned-byte |
X |
X |
|
values |
* |
||
vector |
X |
X |
X |
The coerce function may be used to convert an object to an equivalent object of another type.
The type-of function may be used to obtain a type specifier describing the type of a given object. The getltype function is a Star Sapphire LISP function which returns the same value as type-of but distinguishes fixnums and bignums from 'true' integers.
4.2 Type Specifier Lists
Type specifier lists are essentially a little built-in mini-language for specifying types. A valid type specifier list has one of the following symbols at its head:
satisfies
member
eql
not
and
or
array
simple-array
vector
complex
mod
signed-byte
unsigned-byte
integer
rational
float
short-float
single-float
double-float
long-float
real
string
simple-string
simple-base-string
bit-vector
simple-vector
simple-bit-vector
Although type specifier lists are not functions, they are informally discussed with similar terminology, in particular as though they were predicates. They are said to have arguments; a boolean value is said to be returned from them. This is not exactly what is going on but will have to do since the specification is unclear on this point.
In actuality, the type specifier lists are not evaluated per se; they are being compared internally with a specific object in a restricted set of contexts. The return value from this comparision is passed to the surrounding LISP form.
The implication of this for the programmer is as follows: Type specifier lists are always quoted; they may or may not have any meaning if evaluated by themselves. Type specifier lists are only meaningful when submitted as an argument to the following functions, special forms or macros:
coerce
typep
typecase
the
make-sequence
concatenate
map
merge
make-array :element-type
Furthermore, in some contexts, such as coerce or make-sequence, which create objects, the more general type specifier syntax (in particular type lists with member, and, or and not) is not meaningful and may even raise an error.
Refer to the following other sections for more information:
4.2.1 Examples of List Type Specifiers
4.2.2 Type List Syntax
4.2.1 Examples of List Type Specifiers
Here is an array which can only store symbols and bit-vectors:
(setq x (make-array (2 20) :element-type '(or symbol bit-vector)))
Any attempt to store anything but a symbol or a bit-vector into this array will produce an error.
A more useful example of type lists is using typep to check on an objects type before using it:
(if (typep x '(and number (or ratio float)))
... ; code which expects x to be a ratio or floating point number
)
This can also be done using the special form the:
(let ((x (the '(and number (or ratio float)) y)))
... ; code which expects y to be a ratio or
... ; floating point number and binds it to x
)
will produce an error if x is not a ratio or float.
Some type specifiers define ranges of numbers. For instance, (integer 3 10) means the integers between the values 3 and 10. For example:
(
typep 42 '(integer 3 10)) => nil(
typep 5 '(integer 3 10)) => tOther type specifiers define restricted classes of sequences or arrays. The vector type specifier list can optionally specify a type and a length. For instance, '(vector (string 10) 5) means any vector of length 10 of strings of length 5.
In some cases, the symbol * is used in type specifier lists to indicate unspecified. For instance '(vector * 100) indicates all vectors of length 100; '(vector integer *) indicates all vectors of type integer. Note that '(vector * 100) can also be written '(vector t 100) since t indicates "any type"; '(vector integer *) can also be written '(vector integer) since the arguments to the type specifier vector are optional. Just '(vector) is the same as the symbol 'vector.
Note that '(vector t 100) is actually different from (vector * 100) in a subtle way. For a discussion of the issue, see CLTL2 page 54-5.
4.2.2 Type List Syntax
The syntax for the type specifier lists is complicated and not specified precisely in CLTL. For this reason, we have put together a more exact specification of this syntax, based on CLTL and other references.
Following is the exact specification of the syntax of all type specifier lists supported in this implementation. The specification uses the Sapiens grammar description conventions: A symbol stands for a non-terminal, a quoted string (surounded by single quotes) stands for a terminal. The operators are: ;(rule separator), -> (rewrite), comma (alternates), + (adjoin), * (repeat n times or more), / (repeat n times or less) and dot (symbol attributes) in that order of precedence. Note that ~minusp means not minusp.
typespec-> typespecatom, typespeclist;
typespeclist ->
'(' + 'satisfies' + symbol +')',
'(' + 'member' + obj*0 + ')',
'(' + 'eql' + obj +')',
'(' + 'not' + typespec + ')',
'(' + ('and', 'or') + typespec*0 +')',
'(' + '('array', 'simple-array') +
(otypespec + (onatintspec, ('(' + onatintspec*0 + ')'))/1)/1 + ')',
'(' + 'vector' + (otypespec + onatintspec/1)/1 + ')',
'(' + 'complex' + otypespec/1 + ')',
'(' + 'mod' + natint + ')',
'(' + ('signed-byte','unsigned-byte') + onatintspec/1 +')',
'(' + ('integer', 'rational', 'float', 'short-float',
'single-float', 'double-float', 'long-float', 'real') +
onumspec/2 + ')',
'(' + ('string', 'simple-string', 'simple-base-string',
'bit-vector', 'simple-vector', 'simple-bit-vector')
+ onatintspec/1 + ')'
;
otypespec -> typespec, '*';
natint -> integer.~minsup;
onatintspec -> integer.~minusp, '*';
onumspec -> number.type, '*', '(' + number.type + ')'