Moving onwards, the casual Lisp programmer arriving from C++ might not have encountered deftype in his or her reading. There’s a fine description and example of the macro in the CLHS. This macro allows the programmer to define a new type specifier.
So, why might the programmer want to create new type specifiers? Most commonly, programmers either want to use them along with declare and the to provide compiler hints, helping the optimizer to know what underlying types are being used. The programmer-defined type specifier is somewhat similar to a C++ typedef, by defining your own type specifier you can easily alter code when you have to change the underlying type, without having to search through your code for occurrences of the type.
New type specifiers also might be useful in typecase statements:
(defun equidimensional (a) (or (< (array-rank a) 2) (apply #'= (array-dimensions a)))) (defun all-ints (a) (let ((len (array-total-size a))) (dotimes (i len) (unless (integerp (row-major-aref a i)) (return-from all-ints nil))) t)) (deftype square-matrix (&optional type size) `(and (array ,type (,size ,size)) (satisfies equidimensional))) (deftype integer-square-matrix (&optional size) `(and (square-matrix integer ,size) (satisfies all-ints))) (defun demonstrate () (let ((objects (list :ABC (make-array '(2 3)) (make-array '(2 2) :initial-element 1) (make-array '(2 2) :initial-element 1.1)))) (dolist (obj objects) (format t "~S~26T" obj) (typecase obj (integer-square-matrix (format t "is an integer square matrix")) (square-matrix (format t "is a square matrix")) (array (format t "is a non-square matrix")) (t (format t "is a non-matrix"))) (format t "~%"))))
Producing output:
CL-USER> (demonstrate) :ABC is a non-matrix #2A((0 0 0) (0 0 0)) is a non-square matrix #2A((1 1) (1 1)) is an integer square matrix #2A((1.1 1.1) (1.1 1.1)) is a square matrix NIL