Generalized reference over structured data by pairwise reduction of arbitrary place identifiers for Common Lisp.
The interface is simple and minimalist by design, primarily intended for streamlined work with hierarchical data, such as that imported automatically from another language or format that may not follow Lisp style conventions and best-practices. Support is also included for the SERIES library because I happen to use it a lot.
Inspired by, and an alternative to, the ACCESS library, and SERAPEUM's
vref
and href
forms.
Reference a place by the sequence of place identifiers in desending order, using
the ref
function or the $
convenience macro. Referenced places are typically
SETF-able where it makes sense for them to be so.
Support is included for the following types:
- arbitrary place names identified by symbol or string
- symbol values, lexical and dynamic, by package
- symbol p-list values
- pathname components to navigate directories and files like any other structured data
- CLOS objects and slot values, with or without accessor functions
- structs and struct slots by key
- hash-tables by key
- p-lists by key
- a-lists by key
- proper lists by index
- vectors by index
- arrays by indices
- series objects by selection, index, range, or function-key
To extend for your custom data types, specialize the generic function %ref
.
Download the software to a place ASDF can find it, such as #P"~/common-lisp"
.
Then in your favourite REPL:
(ql:quickload :generalized-reference)
(use-package :generalized-reference)
Association Lists allow lookups by quoted-symbol or name-string. Note that the name-string is case-sensitive.
Keyword-symbol lookup for Association Lists is not presently supported, but may be in a future update.
(defparameter *alist* '((a . 1) (b . 2) (c . 3)))
($ *alist* 'a)
=> 1
($ *alist* "A")
=> 1
($ *alist* :a)
=> NIL
($ *alist* "a")
=> NIL
Property Lists allow lookups by keyword-symbol, quoted-symbol, or name-string. Note that the name-string is case-sensitive.
(defparameter *plist* '(:a 1 :b 2 :c 3))
($ *plist* :a)
=> 1
($ *plist* 'a)
=> 1
($ *plist* "A")
=> 1
($ *plist* "a")
=> NIL
Hash Tables currently support lookup by their internal hash-key. To allow lookup
for string-based hash-keys, remember to set the equality test to equal
when
defining the hash table.
When a hash-key isn't found in a hash table, ref
returns the keyword symbol
:NOT-FOUND
, while returning NIL
means the hash-key is present in the table
but has its value set to NIL
.
Note: For this example we're also going to use the DICT
constructor function
from the Serapeum library, a dependency of generalized-reference already
available in your Lisp Image. By default it uses equal
comparison for hash-key
lookups, which is exactly what we need.
(use-package :serapeum)
(defparameter *hash* (dict :a 1 :b 2 :c 3 "D" 4))
($ *hash* :a)
=> 1
($ *hash* "D")
=> 4
($ *hash* :d)
=> :NOT-FOUND
Vectors allow lookup by index.
(defparameter *vector* (vector 1 2 3 4))
($ *vector* 0)
=> 1
Arrays allow lookup by a list of indices.
(defparameter *array* (make-array '(2 2) :initial-contents '((1 2) (3 4))))
($ *array* '(0 0))
=> 1
($ *array* '(1 1))
=> 4
This library has been built and tested successfully on macOS using the following Lisp implementations:
- LispWorks 8.0.1 (64-bit)
- Allegro CL 10.1
- SBCL 2.2.5
- Clozure-CL 1.12.1
- GNU CLISP 2.49.92
- ECL 21.2.1
- ABCL 1.9.0
And does not build due to dependency failure on:
- CLASP CL 1.0.0
Copyright © 2022, "the Phoeron" Colin J.E. Lupton
Released under the MIT License. See generalized-reference/LICENSE for more information.