Skip to content

LISP - Vector Functions

Vectors are a fundamental sequence type in Common Lisp, providing O(1) random access to elements. This chapter explores key functions for creating, modifying, and operating on vectors, following modern and idiomatic practices.

Individual elements of a vector are modified using (setf aref).

aref (ARray REFerence) is the universal function for accessing elements of any array, including vectors. svref is a specialized version for simple vectors that can be faster, but aref is more general and usually sufficient.

(let ((my-vector (vector 10 20 30 40)))
(format t "Original vector: ~a~%" my-vector)
;; Modify the element at index 2 (the third element)
(setf (aref my-vector 2) 99)
(format t "Modified vector: ~a~%" my-vector))
Original vector: #(10 20 30 40)
Modified vector: #(10 20 99 40)

The fill function efficiently sets all or a subsequence of a vector’s elements to a single value.

(let ((my-vector (vector 1 2 3 4 5)))
(format t "Original vector: ~a~%" my-vector)
;; Fill the entire vector with 0
(fill my-vector 0)
(format t "Filled vector: ~a~%" my-vector))
Original vector: #(1 2 3 4 5)
Filled vector: #(0 0 0 0 0)

You can inspect a vector’s properties, such as its length and element type.

;; A general-purpose vector holds any type of element (T)
(let ((general-vector (vector "hello" 42 #\c)))
(format t "Vector: ~a~%" general-vector)
(format t " Length: ~a~%" (length general-vector))
(format t " Element Type: ~a~%" (array-element-type general-vector)))
(terpri)
;; A specialized vector is optimized for a specific type, like integers
(let ((specialized-vector (make-array 3 :element-type 'fixnum
:initial-contents '(100 200 300))))
(format t "Vector: ~a~%" specialized-vector)
(format t " Length: ~a~%" (length specialized-vector))
(format t " Element Type: ~a~%" (array-element-type specialized-vector)))
Vector: #("hello" 42 #\c)
Length: 3
Element Type: T
Vector: #(100 200 300)
Length: 3
Element Type: FIXNUM

Common Lisp’s functional heritage shines with higher-order functions like map and reduce, which can operate on vectors to produce new results without mutation.

The map function applies a function to each element of a sequence, returning a new sequence. The first argument 'vector specifies that the result should be a vector.

(let* ((original (vector 1 2 3 4 5))
(doubled (map 'vector #'(lambda (x) (* x 2)) original)))
(format t "Original: ~a~%" original)
(format t "Doubled: ~a~%" doubled))
Original: #(1 2 3 4 5)
Doubled: #(2 4 6 8 10)

The reduce function combines the elements of a sequence into a single value using a binary function.

(let* ((numbers (vector 1 2 3 4 5 6))
(sum (reduce #'+ numbers)))
(format t "Numbers: ~a~%" numbers)
(format t "Sum: ~a~%" sum))
Numbers: #(1 2 3 4 5 6)
Sum: 21

When writing functions that operate on vectors, it’s crucial to test them. While full testing frameworks like FiveAM or Prove are recommended for projects, you can perform simple checks using assert.

(defun sum-vector (vec)
(reduce #'+ vec))
;; Test cases
(assert (= (sum-vector (vector 1 2 3)) 6))
(assert (= (sum-vector (vector)) 0))
(assert (= (sum-vector (vector -1 1)) 0))
(format t "All sum-vector tests passed!~%")

This simple approach validates that your function works for typical inputs, empty inputs (an edge case), and other scenarios.