common lisp type vector of fixnums

54 views Asked by At

In Common Lisp I can check a type like:

(typep #(1 2 3) 'sequence)
;; returns T

And so I can use sequence in (declaim (ftype ... to specify a parameter of a function.

Is it possible to make the type even more specific and force a parameter to be a vector from fixnum?

Example:

(declaim (ftype (function (fixnum) sequence) abc))

(defun abc (n) #(n))

This function and its type definition works as expected. But can I define the return type more specific? Instead of sequence something like (vector fixnum)?

2

There are 2 answers

0
Rainer Joswig On BEST ANSWER

Possible type declarations for vectors

The Common Lisp HyperSpec provides an overview of type specifiers.

We can follow through the table there to the system class vector. This tells us that we can use vector as a Compound Type Specifier:

vector [{element-type | *} [{size | *}]]

Above is a syntax definition.

So declarations can use vector types like:

(vector)              ; any vector
(vector *)            ; any vector 
(vector * *)          ; any vector
(vector fixnum *)     ; vector of fixnums of any size
(vector * 42)         ; vector of length 42
(vector fixnum 42)    ; vector of fixnums and vector length 42

If you move the class chain upwards, you can see that the system class sequence does not provide such a syntax.

Note on returning a vector

If you write (defun abc (n) #(n)), then it won't return the argument, but the symbol n. Elements of a literal vector are not evaluated.

CL-USER 24 > (defun abc (n) #(n))
ABC

Above returns a literal vector of a symbol. literal also means that you should not modify it.

CL-USER 25 > (abc 42)
#(N)

There is a backquote syntax for vectors:

CL-USER 26 > (defun abc (n) `#(,n))
ABC

CL-USER 27 > (abc 42)
#(42)

We can also call the function vector, which will create a vector with the argument values as its contents.

CL-USER 28 > (defun abc (n) (vector n))
ABC

CL-USER 29 > (abc 42)
#(42)
3
coredump On

You can write

(coerce #(1 2 3) '(vector fixnum))

Or, more generally, use make-array to specify the type:

(make-array 3 :element-type 'fixnum :initial-contents '(1 2 3))

Note that the element type in arrays is an information mostly used between Lisp and the implementation platform, to possibly use a specialized type of array that is more compact, more efficient, etc. and not a type that necessarily restrict what kind of value you can put inside.

For example, a vector as follows:

(make-array 10 :element-type '(member 1 2 3))

is described in SBCL has having the following type:

Element type: (UNSIGNED-BYTE 2)

But is initialized with zeroes:

#(0 0 0 0 0 0 0 0 0 0)

But zero is not a value of the declared type.

It all boils down to what the upgraded-element-type of the array is, which is the type of value that can fit in the specialized array.