(apply (function append) (mapcar #'g ...)) just mapcan ( update: with the usual caveats about destructive updating and cited lists, see also this ):
(defun describe-paths (location edges) (mapcan
Recursion is good for thinking, for understanding. But actually its use in the code has a price.
Your recursive rewrite tail recursive modulos cons ; no Lisp has this AFAIK optimization, although it was first described in 1974 , in Lisp.
So, what you wrote is good as an executable specification.
But Common Lisp is a practical language. In particular, it has many iteration coding methods. Remember that iterative processes are our goal; recursive processes are terrible, efficient. Therefore, when we write code that is syntactically recursive, we still want it to describe an iterative process (one that works in a constant stack space).
A common Lisp, which is a practical language, would make us just write a loop directly. For one,
(defun describe-paths-loop (location edges &aux (res (list 1)) (p res)) (dolist (x (cdr (assoc location edges)) (cdr res)) ; the return form (setf (cdr p) (describe-path x)) (setf p (last p))))
guaranteed to work in a constant stack space.
update:, this destroys the concatenation of the lists returned by describe-path , so care should be taken not to return lists with the same last cons cell to individual calls, or this could create a circular composition. Alternatively, the call to describe-path can be completed by calling copy-list . Of course, if describe-path was supposed to return a list that is already circular, last also falls into the loop here.