I have a nested list, and I am trying to non-destructively replace all its elements (inside the nested list as well). That is, given my input list
\'(1 \'(2
Mark's answer and wdebeaum's answer explain why you're getting the results that you're getting; the nested quotes mean you've actually got a list like (1 (quote (2 3 4)) (quote (5 6 7)) 8 9)
, and you're replacing the symbol quote
with 0
, and that's why you get (0 (0 (0 0 0)) (0 (0 0 0)) 0 0)
. You probably want just '(1 (2 3 4) (5 6 7) 8 9)
with no nested quotes.
It's worth pointing out that Common Lisp already provides a functions for non-destructively substituting in cons-trees, though: subst, subst-if, and subst-if-not. There are destructive versions, too: nsubst, nsubst-if, and nsubst-if-not. In particular, for this case you can just replace everything that's not a list with 0, either by using the complement function with listp and subst-if, or using listp and subst-if-not:
;; With `extra' elements because of the quotes:
(subst-if-not 0 #'listp '(1 '(2 3 4) '(5 6 7) 8 9))
;=> (0 (0 (0 0 0)) (0 (0 0 0)) 0 0)
(subst-if 0 (complement #'listp) '(1 '(2 3 4) '(5 6 7) 8 9))
;=> (0 (0 (0 0 0)) (0 (0 0 0)) 0 0)
;; With no `extra' elements:
(subst-if-not 0 #'listp '(1 (2 3 4) (5 6 7) 8 9))
;=> (0 (0 0 0) (0 0 0) 0 0)
(subst-if 0 (complement #'listp) '(1 (2 3 4) (5 6 7) 8 9))
;=> (0 (0 0 0) (0 0 0) 0 0)
If you wanted to take the hybrid approach suggested in wdebeaum's answer where you don't replace quotes, you can do that do:
(subst-if 0 (lambda (x)
(not (or (listp x)
(eq 'quote x))))
'(1 '(2 3 4) '(5 6 7) 8 9))
;=> (0 '(0 0 0) '(0 0 0) 0 0)
(subst-if-not 0 (lambda (x)
(or (listp x)
(eq 'quote x)))
'(1 '(2 3 4) '(5 6 7) 8 9))
;=> (0 '(0 0 0) '(0 0 0) 0 0)