Generalized reference over structured data by pairwise reduction of arbitrary place identifiers for Common Lisp.

Upstream URL


"the Phoeron" Colin J.E. Lupton




Quicklisp MIT License

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, ACCESS 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

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

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

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)


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


Copyright © 2022, "the Phoeron" Colin J.E. Lupton

Released under the MIT License. See generalized-reference/ for more information.

Dependencies (6)

  • alexandria
  • closer-mop
  • serapeum
  • series
  • split-sequence
  • trivial-types

Dependents (0)

    • GitHub
    • Quicklisp