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, namely1
and(2 . 3)
. Sincemap-into
does 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-into
with this sequence, which happens to be an improper list.map-into
expects 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-tree
in 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 thecdr
slot: