:fill-pointer
argument. For instance, the following call to MAKE- ARRAY
makes a vector with room for five elements; but it looks empty because the fill pointer is zero:
(make-array 5 :fill-pointer 0) ==> #()
To add an element to the end of a resizable vector, you can use the function VECTOR- PUSH
. It adds the element at the current value of the fill pointer and then increments the fill pointer by one, returning the index where the new element was added. The function VECTOR- POP
returns the most recently pushed item, decrementing the fill pointer in the process.
(defparameter *x* (make-array 5 :fill-pointer 0))
(vector-push 'a *x*) ==> 0
*x* ==> #(A)
(vector-push 'b *x*) ==> 1
*x* ==> #(A B)
(vector-push 'c *x*) ==> 2
*x* ==> #(A B C)
(vector-pop *x*) ==> C
*x* ==> #(A B)
(vector-pop *x*) ==> B
*x* ==> #(A)
(vector-pop *x*) ==> A
*x* ==> #()
However, even a vector with a fill pointer isn't completely resizable. The vector *x*
can hold at most five elements. To make an arbitrarily resizable vector, you need to pass MAKE- ARRAY
another keyword argument: :adjustable
.
(make-array 5 :fill-pointer 0 :adjustable t) ==> #()
This call makes an VECTOR-PUSH- EXTEND
, which works just like VECTOR-PUSH
except it will automatically expand the array if you try to push an element onto a full vector—one whose fill pointer is equal to the size of the underlying storage.[122]
All the vectors you've dealt with so far have been
One of these you've seen already—strings are vectors specialized to hold characters. Strings are important enough to get their own read/print syntax (double quotes) and the set of string-specific functions I discussed in the previous chapter. But because they're also vectors, all the functions I'll discuss in the next few sections that take vector arguments can also be used with strings. These functions will fill out the string library with functions for things such as searching a string for a substring, finding occurrences of a character within a string, and more.
Literal strings, such as 'foo'
, are like literal vectors written with the #()
syntax—their size is fixed, and they must not be modified. However, you can use MAKE- ARRAY
to make resizable strings by adding another keyword argument, :element- type
. This argument takes a CHARACTER
as the :element-type
argument. Note that you need to quote the symbol to prevent it from being treated as a variable name. For example, to make an initially empty but resizable string, you can write this:
(make-array 5 :fill-pointer 0 :adjustable t :element-type 'character) ''
Bit vectors—vectors whose elements are all zeros or ones—also get some special treatment. They have a special read/print syntax that looks like #*00001111
and a fairly large library of functions, which I won't discuss, for performing bit-twiddling operations such as 'anding' together two bit arrays. The type descriptor to pass as the :element-type
to create a bit vector is the symbol BIT
.
As mentioned earlier, vectors and lists are the two concrete subtypes of the abstract type
The two most basic sequence functions are LENGTH
, which returns the length of a sequence, and ELT
, which allows you to access individual elements via an integer index. LENGTH
takes a sequence as its only argument and returns the number of elements it contains. For vectors with a fill pointer, this will be the value of the fill pointer. ELT
, short for ELT
will signal an error if the index is out of bounds. Like LENGTH
, ELT
treats a vector with a fill pointer as having the length specified by the fill pointer.
(defparameter *x* (vector 1 2 3))
(length *x*) ==> 3
(elt *x* 0) ==> 1
(elt *x* 1) ==> 2
(elt *x* 2) ==> 3
(elt *x* 3) ==>
ELT
is also a SETF
able place, so you can set the value of a particular element like this:
(setf (elt *x* 0) 10)
*x* ==> #(10 2 3)
While in theory all operations on sequences boil down to some combination of LENGTH
, ELT
, and SETF
of ELT
operations, Common Lisp provides a large library of sequence functions.