Search code examples
common-lispcons

Convert nested hash-tables to a-list how to ensure the creation dotted pairs


I wrote the following function to convert nested hash-tables to an a-list:

(defun hash-table->alist* (ht)
  (loop for k being the hash-keys in ht using (hash-value v)
        collect (cons k
                      (etypecase v
                        (integer v)
                        (hash-table (hash-table->alist* v))))))

It works fine for non nested hash-tables:

> (hash-table->alist* (dict :a 1 :b 23 :c 4))
((:A . 1) (:B . 23) (:C . 4))

But when I use it on nested hash-tables I loose the dotted-pairs on the way:

> (hash-table->alist* (dict :session (dict :user (dict :fullname 23))))
((:SESSION (:USER (:FULLNAME . 23))))

How can I ensure the creation of a dotted pair instead of appending to the front of a list?


Solution

  • I guess you expected:

    ((:SESSION . ((:USER . ((:FULLNAME . 23))))))
    

    However, if the cdr of a cons cell contains a list, this implies a list structure, which is printed without dot and without nested parentheses. This is how lists are defined: (A . (B)) is (A B). So, this is exactly the same structure:

    ((:SESSION (:USER (:FULLNAME . 23))))
    

    This confusion is unavoidable, because the fact that a given list structure is meant as an alist is not possible to discern from the structure itself.