LISP - Specialized Vectors
Lisp - Specialized Vectors
Section titled “Lisp - Specialized Vectors”A standard Lisp vector is a general-purpose container that can hold any type of Lisp object. This flexibility comes at a cost: each element requires storage for a type tag and a pointer, a concept known as boxing. A specialized vector, in contrast, is optimized to hold elements of only one specific, primitive type. This offers significant advantages in performance and memory usage.
Why Use Specialized Vectors?
Section titled “Why Use Specialized Vectors?”- Memory Efficiency: By storing raw data values directly without boxing (e.g., storing a raw 8-bit integer instead of a pointer to an integer object), specialized vectors use significantly less memory.
- Increased Performance: Accessing elements is much faster. The CPU can work with data directly, improving cache locality and enabling powerful SIMD (Single Instruction, Multiple Data) optimizations by the compiler.
- Type Safety: The Lisp system enforces the type restriction. Attempting to store an element of the wrong type will signal an error, catching bugs early.
- Foreign Function Interface (FFI): They are essential for interfacing with libraries written in other languages like C, as they map directly to C-style arrays in memory.
Creating and Using Specialized Vectors
Section titled “Creating and Using Specialized Vectors”You create a specialized vector by providing the :element-type argument to make-array. The system will automatically choose the most compact representation possible.
Vector of Integers
Section titled “Vector of Integers”You can create vectors for various integer sizes. (unsigned-byte 8) is perfect for holding bytes, for instance.
;; Create a vector to hold 5 integers, each an unsigned byte (0-255).;; It is initialized with zeros.(let ((byte-vector (make-array 5 :element-type '(unsigned-byte 8)))) (print byte-vector) ;; -> #(0 0 0 0 0)
;; Assign some values (setf (aref byte-vector 0) 10) (setf (aref byte-vector 1) 255) (print byte-vector) ;; -> #(10 255 0 0 0)
;; This would signal a type error, as 300 is out of range for an unsigned-byte 8. ;; (setf (aref byte-vector 2) 300))Vector of Bits (Bit-Vector)
Section titled “Vector of Bits (Bit-Vector)”A bit-vector is an extremely compact way to store a sequence of boolean (0 or 1) values. Lisp provides a convenient reader macro #* for creating them literally.
;; Create a bit-vector using the reader macro(let ((bit-v #*10110)) (print bit-v) ;; -> #*10110
;; Access an element (print (aref bit-v 2)) ;; -> 1
;; Modify an element (setf (aref bit-v 2) 0) (print bit-v)) ;; -> #*10010Vector of Characters (String)
Section titled “Vector of Characters (String)”A Lisp string is, by definition, a specialized one-dimensional array whose elements are of type character.
;; These are effectively equivalent(defvar string1 "Hello")(defvar string2 (make-array 5 :element-type 'character :initial-contents '(#\H #\e #\l #\l #\o)))
(print (aref string1 1)) ; -> #\eVector of Floating-Point Numbers
Section titled “Vector of Floating-Point Numbers”Specialized float vectors are critical for scientific and numerical computing.
;; Create a vector of single-precision floating-point numbers.(let ((float-vec (make-array 3 :element-type 'single-float))) (setf (aref float-vec 0) 3.14f0) (setf (aref float-vec 1) 1.618f0) (print float-vec));; -> #(3.14 1.618 0.0)When to Use Specialized Vectors
Section titled “When to Use Specialized Vectors”Choose specialized vectors when you are:
- Dealing with large amounts of homogeneous, primitive data (e.g., numbers, characters).
- Writing performance-critical code where memory bandwidth and cache performance are important (e.g., game development, data analysis, image processing).
- Handling binary data, such as reading from files or network sockets.
- Interfacing with C or other systems-level libraries.
For general-purpose programming where flexibility is more important than raw performance, or when you need to store a mix of different object types, a standard vector is often the more convenient choice.