Name of the package is "build-trees" {lower case} with nickname BTR .It exports the functions new , append , tree , tree? , level-up , level-down , finish , info . Note that they have ordinary names and append shadows the standard function by the same name so the idea is that you use the BTR: prefix to call the functions rather than do (use-package "build-trees") . The library makes it easy to create trees i.e. nested lists. I mostly use it to construct the expansion of macros. There will be examples of that further down. In order to get a taste of the functionality , I will start with short examples. In the following , a line starting with > means the REPL prompt and a line starting with => means what the previous form returned. I will only give return values when they are relevant , some of the functions exist for the side effects. > (defparameter tr (btr:new)) Creates a new tree. > (btr:tree tr) => NIL btr:tree returns what the tree has so far. Since we have not added anything to it , it returns NIL . > (btr:append tr 123) > (btr:tree tr) => (123) > (btr:append tr '(a b c)) > (btr:tree tr) => (123 (A B C)) > (btr:append tr '(a b c) t) > (btr:tree tr) => (123 (A B C) A B C) The optional 3rd argument to btr:append is a boolean with default value NIL .It controls whether the object we append will be appended as one or copied one element at a time ; in the latter case , it must be a "proper tree" meaning a proper list and every element which is a cons must also be a proper list and so on recursively. So the call (btr:append tr '(a b c) t) is equivalent to (btr:append tr 'a) (btr:append tr 'b) (btr:append tr 'c) but obviously faster and more convenient. If the 3rd argument is NIL , any object will do. > (btr:level-up tr) It starts a nested subtree. > (btr:append tr 456) > (btr:tree tr) => (123 (A B C) A B C (456)) > (btr:append tr '(d e)) > (btr:tree tr) => (123 (A B C) A B C (456 (D E))) > (btr:level-up tr) > (btr:append tr 11) > (btr:tree tr) => (123 (A B C) A B C (456 (D E) (11))) > (btr:level-down tr) It goes down 1 level i.e. it ends a nested subtree. > (btr:append tr 12) > (btr:tree tr) => (123 (A B C) A B C (456 (D E) (11) 12)) > (btr:level-down tr) > (btr:append tr 13) > (btr:tree tr) => (123 (A B C) A B C (456 (D E) (11) 12) 13) > (btr:finish tr) => (123 (A B C) A B C (456 (D E) (11) 12) 13) After calling btr:finish on a tree , no futher modifications are allowed ; passing the tree as argument to btr:level-up or btr:level-down or btr:append will signal an error. Calling btr:tree or btr:finish will return the final form of the tree. (btr:info tr) returns -1 if and only if tr is finished. > (setq tr (btr:new)) > (btr:info tr) => 0 This is the level of the tree we are currently constructing where 0 is the lowest level. > (btr:level-up tr 2) > (btr:info tr) => 2 > (btr:append tr '((A)) t) > (btr:tree tr) => ((((A)))) > (btr:info tr) => 2 > (btr:append tr '((B)) t :no-descend) > (btr:info tr) => 3 > (btr:append tr 5) > (btr:tree tr) => ((((A) (B 5)))) btr:append takes an optional 4th argument which must be :no-descend or an integer. If the 4th argument is given then the 3rd must not be NIL .As mentioned , in a call (btr:append tr object t) , the elements of object get inserted into tr one at a time. Every time a subtree appears in object , we go 1 level up in tr and every time a subtree ends in object , we go 1 level down in tr .With a 4th argument of :no-descend , we remain at the same level in tr as the level of the final atom in object so any new elements will be inserted in tr at that level. > (btr:append tr '(((C)) (D)) t :no-descend) > (btr:tree tr) => ((((A) (B 5 ((C)) (D))))) > (btr:append tr 6) > (btr:tree tr) => ((((A) (B 5 ((C)) (D 6))))) If the 4th argument to btr:append is an integer N then , after adding to tr the final atom of object , we do not descend below level N . (dolist (l '(:no-descend 3 2 1 0 -1 -2 -3)) (let ((tr (btr:new))) (btr:level-up tr 3) (btr:append tr 'A) (format t "~S~%" (btr:tree tr)) (btr:append tr '((((((B)))))) t l) (format t "~S ~S ~S~%" l (btr:info tr) (btr:tree tr)) (btr:append tr 'C) (format t "~S~% ---~%" (btr:tree tr)))) prints ((((A)))) :NO-DESCEND 8 ((((A (((((B))))))))) ((((A (((((B C))))))))) --- ((((A)))) 3 6 ((((A (((((B))))))))) ((((A (((((B)) C))))))) --- ((((A)))) 2 5 ((((A (((((B))))))))) ((((A (((((B))) C)))))) --- ((((A)))) 1 4 ((((A (((((B))))))))) ((((A (((((B)))) C))))) --- ((((A)))) 0 3 ((((A (((((B))))))))) ((((A (((((B))))) C)))) --- ((((A)))) -1 2 ((((A (((((B))))))))) ((((A (((((B)))))) C))) --- ((((A)))) -2 1 ((((A (((((B))))))))) ((((A (((((B))))))) C)) --- ((((A)))) -3 0 ((((A (((((B))))))))) ((((A (((((B)))))))) C) --- On first look it may seem counterintuitive that in lines like :NO-DESCEND 8 ((((A (((((B))))))))) B has been inserted with 5 opening parentheses whereas the call which did the insertion is (btr:append tr '((((((B)))))) t l) where B has 6 opening parentheses.But this is consistent with the example given above : > (btr:append tr '(a b c)) > (btr:tree tr) => (123 (A B C)) > (btr:append tr '(a b c) t) > (btr:tree tr) => (123 (A B C) A B C) THE FULL INTERFACE @ Function new (&optional object treat-as-tree? level) Defaults for the optional arguments are NIL . The function creates and returns a new "tree-builder" object. Such an object must be the first argument to functions level-up , level-down , append , tree , finish , info .You should treat it as an opaque type i.e. only use it as the documentation here specifies. The optional arguments have the same meaning as for btr:append meaning that doing (let ((newtr (btr:new some-object boolean integer-or-symbol))) ...code...) is the same as doing (let ((newtr (btr:new))) (btr:append newtr some-object boolean integer-or-symbol) ...code...) Running time : with 2nd argument NIL constant otherwise same as btr:append . @ Function tree? (object) The argument is an arbitrary Common Lisp object. The function returns a generalised boolean which will be true if and only if object is of type tree-builder . Running time : constant. @ Function level-up (tr &optional (n 1)) The first argument must be a tree-builder object which is not "finished" i.e. one for which (btr:info tr) does not return -1 . n must be an integer >= 1 .The function starts a subtree of tr n levels above where we are at the present stage of construction. The examples above show how this works in practice. The return value should be ignored i.e. the function only exists for the side effect. Running time : linear in n . @ Function level-down (tr &optional (n 1)) The first argument must be a tree-builder object which is not "finished" . n must be an integer >= 1 .The function terminates the n highest levels of the tree we are building. If this means that the current level of tr goes negative then tr becomes finished. You can still see the final content of the tree by calling btr:tree on it : (let ((tr (btr:new))) (btr:level-up tr 3) (btr:append tr 'a) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) (btr:level-down tr 2) (btr:append tr 'b) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) (btr:level-down tr) (btr:append tr 'c) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) (btr:level-down tr) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) (format t "Now the tree is finished and calling btr:append on it will ~ give an error~%") ) prints Current level is 3 Tree has ((((A)))) Current level is 1 Tree has ((((A)) B)) Current level is 0 Tree has ((((A)) B) C) Current level is -1 Tree has ((((A)) B) C) Now the tree is finished and calling btr:append on it will give an error The return value of level-down should be ignored i.e. the function only exists for the side effect. Running time : linear in n . @ Function tree (tr) tr must be a tree-builder object. If it is finished , the function will return what the final content of the tree is. If it is not finished , it will return the content of the tree so far. If any levels have been created with level-up but nothing has been added to them {with btr:append} then they will be NIL. Running time : an upper bound is linear in N+M where N is the number of atoms in the tree and M the number of levels under construction. For a more precise estimate you will have to look at the source code , any attempt to express the same in words will just be more complicated. @ Function append (tr object &optional treat-as-tree? level) Default for treat-as-tree? is NIL ; for level is 0. tr must be a tree-builder object which is not finished . n must be an integer or the symbol :no-descend . The function appends object to the tree being constructed. How the arguments treat-as-tree? and level affect the functionality was explained in the examples above. As with level-down , if argument level is a negative integer and small enough that it will make the current level of the tree negative , then the tree is finished : (let ((tr (btr:new))) (btr:append tr '((z)) t 0) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) (btr:append tr '((m)) t -1) (format t "Current level is ~S Tree has ~S~%" (btr:info tr) (btr:tree tr)) ) prints Current level is 0 Tree has ((Z)) Current level is -1 Tree has ((Z) (M)) Since (btr:info tr) returns -1 , the tree is finished and nothing more can be added to it. The return value of btr:append should be ignored i.e. the function only exists for the side effects. Running time : if treat-as-tree? is NIL , running time is constant ; otherwise running time is linear in N+M+L where * N is the number of atoms in object * M is the number of opening parentheses when object is printed in the canonical manner. For example if object is ((((a))) (((((b)))))) then N is 2 and M is 9. * If level is :no-descend then L is 0 , otherwise L = min { (abs level) , (btr:info tr) } @ Function info (tr) tr must be a tree-builder object. The function returns the level of the tree to which we currently add. It will be an integer and it will be >= 0 if and only if the tree is not finished. Running time : constant. @ Function finish (tr &optional object) tr must be a tree-builder object and the object argument can be any Common Lisp object. If tr is finished already then no object must be given ; in this case it is the same as doing (btr:tree tr) .If tr is not finished then it will become finished and its final content is returned. If object is given , it will be appended to the tree before it is finished but *without* copying (let ((tr (btr:new)) (l1 (list 1 2 3))) (btr:append tr l1) (format t "~S~%" (btr:tree tr)) (setf (first l1) 'one) (format t "~S~%" (btr:tree tr)) (btr:append tr l1 t) (btr:finish tr l1) (setf (second l1) 'two) (format t "~S~%" (btr:tree tr)) ) prints ((1 2 3)) ((ONE 2 3)) ((ONE TWO 3) ONE 2 3 ONE TWO 3) or something similar. Here we append to tr the list l1 3 times .When we do the appending with (btr:append tr l1 t) , l1 gets copied so , when it gets modified after the appending , tr still has the earlier version. With the other appendings l1 does not get copied so when it gets modified this is reflected in tr . Even if object is a tree , it doesn't have to be a proper tree contrary to how btr:append works. The reason is that btr:append must leave the tree-builder object in a state such that further appendings are possible and I couldn't think of a way to achieve this when the 3rd argument to btr:append is T and you append a non proper tree. Perhaps I could have thought of a way with more effort but I didn't think it would be useful. But with btr:finish you aren't going to append anything more to the tree so there is more latitude. It is also a useful functionality as the typed-let example below shows where there is a (btr:finish exp code) .As I've said above , I mostly use the library for writing macros and in macros it is common , after the rest of the expansion has been constructed , to append code given by the user. Running time : if the tree is finished , constant ; otherwise linear in the value of (btr:info tr) . EXAMPLES Below we define a macro typed-let which extends the standard LET .Something like (typed-let (a (b) (c 2) (integer d 4)) ...body...) expands to (let (a (b) (c 2) (d 4)) (declare (type integer d)) ...body...) (defmacro typed-let (vars &body code &aux (exp (btr:new 'let)) (decls (btr:new 'declare)) ) (btr:level-up exp) (dolist (v vars) (cond ((position v '(nil t)) (error "~S encountered where there should have ~ been a variable declaration~%" v)) ((symbolp v) (btr:append exp v)) ((listp v) (cond ((cadddr v) (error "A variable declaration was a list ~ with more than 3 elements~%")) ((caddr v) (btr:append exp (list (cadr v) (caddr v))) (btr:append decls (list 'type (car v) (cadr v)))) (t (btr:append exp v)))) (t (error "Every variable declaration must be a symbol or a list")))) (btr:level-down exp) (btr:append exp (btr:finish decls)) (btr:finish exp code)) The following is a function which accepts as arguments a function foo of 1 argument and a tree tr and returns a fresh tree where each atom A of tr has been replaced by (foo A) . (defun tree-map (foo tr &aux (ntr (btr:new))) (labels ((tmaux (pit hgt &aux (level-begin pit)) (do () (nil) (cond ((eq pit nil) (btr:level-down ntr) (return-from tmaux)) ((atom pit) (error "Function ~s was called with an argument ~ which is not a proper tree.~%The problematic ~ position is at~%~s~%of level~%~s~%~ at height ~s .~%" 'tree-map pit level-begin hgt)) ((atom (car pit)) (btr:append ntr (funcall foo (car pit)))) (t (btr:level-up ntr) (tmaux (car pit) (+ 1 hgt)))) (setq pit (cdr pit))))) (tmaux tr 0)) (btr:finish ntr)) (tree-map (lambda (a) (if (numberp a) (* a a) a)) '(q w 2 (e r 2/3 (t 4 y) 7 #C(1 2) "qwe"))) returns (Q W 4 (E R 4/9 (T 16 Y) 49 #C(-3 4) "qwe")) The following is a macro dfcl which expands to a DEFCLASS using some defaults that I like. For example (dfcl something (class1 class2) ((name :type (vector char8)) (kati) (woo :qwer 123 :wert 555 "wertr") ) more-stuff (even more stuff))) expands to (defclass something (class1 class2) ((name :initarg :name :accessor a-name :type (vector char8)) (kati :initarg :kati :accessor a-kati) (woo :initarg :woo :accessor a-woo :qwer 123 :wert 555 "WERTR")) more-stuff (even more stuff)) (defmacro dfcl (name superclasses slots &rest rest) (let ((tree (btr:new (list 'defclass name superclasses) t))) (btr:level-up tree) (dolist (l slots) (unless (listp l) (error "a slot entry was not a list : ~a" l)) (btr:level-up tree) (let ((sname (first l))) (btr:append tree (list sname :initarg (intern (symbol-name sname) :keyword) :accessor (intern (format nil "A-~a" (symbol-name sname)))) t) (btr:append tree (rest l) t)) (btr:level-down tree)) (btr:level-down tree) (btr:append tree rest t) (btr:finish tree))) CONTACT For questions , comments , bug reports , etc. you can contact me , Spiros Bousbouras , at (map 'string (lambda (a &aux (c (char-code a))) (if (evenp c) (code-char (1+ c)) (code-char (1- c)))) "rqhcntAfl`hm/bnl")