I've coded a function that aims to map into an arbitrary tree of nested proper lists, somewhat analogous to the common lisp function map-into:
(defun map-into-tree (fn tree)
"Destructive mapping into a proper tree."
(cond ((null tree) nil)
((atom (car tree))
(setf (car tree) (funcall fn (car tree)))
(map-into-tree fn (cdr tree)))
(t (map-into-tree fn (car tree))
(map-into-tree fn (cdr tree)))))
(defparameter *tree* '(1 (2) ((3)) (4 5) (6 ((7)))))
*TREE*
(map-into-tree #'1+ *tree*)
NIL
*tree*
(2 (3) ((4)) (5 6) (7 ((8))))
However, I'm not sure how to go about generalizing it for arbitrary nested sequences (like map-into for sequences). Any assistance is appreciated.
You could call
map-into;-)... or equivalently:
Test:
I am not sure what should happen with a tree which contains strings: do we really want to iterate over each character? As a matter of fact, this is what is done here above.
(1 (2 . 3))is a proper list with two elements, namely1and(2 . 3). Sincemap-intodoes not recurse into elements, all it does is calling the function on both those elements. In your comment, this wasprint, which can print improper lists without problems.The second element is a sequence: when you call
map-into-tree, the function recursively callsmap-intowith this sequence, which happens to be an improper list.map-intoexpects a proper sequence and thus fails with improper lists.Please note that in your question, you said:
A tree with improper lists is not a valid input.
Finally, I notice you call destructive functions on literal data, like so:
The quoted list is a constant, modifying it at runtime is undefined behavior. That's why I first used
copy-treein my example.Since there is already a typecase in place, it is sufficient to handle the special case of the
cons; that works regardless of the type of value held in thecdrslot: