Hash tables or dictionaries can be S-expressions.

Some Lisp dialects do not have printed-representations for these; that is a bug, and needs no further discussion.

Common Lisp and Scheme have vectors: they are notated as #(...). That is an S-expression.

CLISP has a #<N>A(...) notation for multidimensional arrays, which it can print and read:

  [8]> (make-array '(2 2) :initial-element 0)
  #2A((0 0) (0 0))
There is a little bit of a restriction in that backquote doesn't support multi-dimensional arrays:

  [2]> (let ((x 42)) `#2A((,x 0) (0 ,x)))
  *** - READ: unquotes may not occur in arrays
But this does work for vectors (as required by ANSI CL, I think):

  [11]> (let ((x 42)) `#(0 ,x 0))
  #(0 42 0)
You might think that #(0 42 0) is just some list variation, but in fact it is a bona-fide vector object, with fast numeric indexing, and without the structural flexibility of lists. Vectors are typically implemented as flat arrays in memory. (Though they could use something else, particularly if large, like radix trees.)

Hash literals look like this in TXR Lisp:

  1> #H(() (a 1) (b 2) (c 3))
  #H(() (a 1) (c 3) (b 2))
You can see the order of the keys changed when it was echoed back. The first element in the #H syntax, (), gives properties. It's empty for the most general form of hash, which uses equal comparison, and doesn't have weak keys or values.

Binary search trees are likewise printable. The #T notation gives a tree (concealing the nodes). The #N notation for individual tree nodes:

  1> (tree)
  #T(())
  2> (tree-insert *1 1)  ; *1 means value from repl line 1
  #N(1 nil nil)
  3> (tree-insert *1 3)
  #N(3 nil nil)
  4> (tree-insert *1 7)
  #N(7 nil nil)
  5> (tree-insert *1 4)
  #N(4 nil nil)
  6> (tree-insert *1 2)
  #N(2 nil nil)
  7> (tree-insert *1 8)
  #N(8 nil nil)
  8> (tree-insert *1 0)
  #N(0 nil nil)
  9> *1
  #T(() 0 1 2 3 4 7 8)
  10> (tree-root *1)
  #N(3 #N(1 #N(0 nil nil) #N(2 nil nil)) #N(7 #N(4 nil nil) #N(8 nil nil)))
The #T notation is readable. It gives the values in order, but they don't have to be specified in order when you write a literal:

  11> #T(() 3 2 1)
  #T(() 1 2 3)
If we ask for the tree root, we see the actual nodes, and how they are linked together:

  12> (tree-root *11)
  #N(2 #N(1 nil nil) #N(3 nil nil))
All these notations are something we can casually use as data in a file or network stream between TXR Lisp programs, or anything else that cares to read and write then notation.

The printed notation of any object in a Lisp is a S-expression. S-expression syntax usually strives for print-read consistency: when an object's printed notation is read by the machine, a similar object is recovere. (In some cases, the original object itself, as with interned symbols).