一个类型标识符是一个类型的名称。最简单的类型标识符是像是 integer
的符号。这些符号形成了 Common Lisp 里的类型层级。在层级的最顶端是类型 t
── 所有的对象皆为类型 t
。而类型层级不是一棵树。从 nil
至顶端有两条路,举例来说:一条从 atom
,另一条从 list
与 sequence
。
一个类型实际上只是一个对象集合。这意味着有多少类型就有多少个对象的集合:一个无穷大的数目。我们可以用原子的类型标识符 (atomic type specifiers)来表示某些集合:比如 integer
表示所有整数集合。但我们也可以建构一个复合类型标识符 (compound type specifiers)来参照到任何对象的集合。
举例来说,如果 a
与 b
是两个类型标识符,则 表示分别由 a
与 b
类型所表示的联集 (union)。也就是说,一个类型 (or a b)
的对象是类型 a
或 类型 b
。
如果 circular?
是一个对于 cdr
为环状的列表返回真的函数,则你可以使用适当的序列集合来表示:
(integer 1 100)
这样的类型标识符用来表示一个有限的类型 (finite type)。
在一个复合类型标识符里,你可以通过在一个参数的位置使用 *
来留下某些未指定的信息。所以
(simple-array fixnum (* *))
描述了指定给 fixnum
使用的二维简单数组 (simple array)集合,而
描述了指定给 finxnum
使用的简单数组集合 (前者的超类型 「supertype」)。尾随的星号可以省略,所以上个例子可以写为:
如果有某些复合类型标识符你想重复使用,你可以使用 deftype
定义一个缩写。这个宏与 defmacro
相似,但会展开成一个类型标识符,而不是一个表达式。通过表达
(deftype proseq ()
'(or vector (and list (not (satisfies circular?)))))
我们定义了 proseq
作为一个新的原子类型标识符:
如果你定义一个接受参数的类型标识符,参数会被视为 Lisp 形式(即没有被求值),与 defmacro
一样。所以
`(and integer (satisfies (lambda (x)
(zerop (mod x ,n))))))
(译注: 注意上面代码是使用反引号 `
)
T
类型标识符会被直译 (interpreted),因此很慢,所以通常你最好定义一个函数来处理这类的测试。