I would like to replace the first few elements of my circular list (1 2 3 4 1 ...) with the same elements in reverse order. I have managed to do it with a loop, but I would like to eliminate it and use a common lisp function which deals with subsequences instead. Can you help me?
CL-USER> (setf *print-circle* t)
T
CL-USER> (defvar *cycle*
(let ((c (list 1 2 3 4)))
(setf (cdr (last c)) c)))
#1=(1 2 3 4 . #1#)
CL-USER> (let ((reversed-part (list 2 1)))
(loop for l on *cycle*
for r in reversed
do (setf (car l) r))
*cycle*)
#1=(2 1 3 4 . #1#)
;; Failed attempts:
CL-USER> (let ((reversed-part (list 2 1)))
(replace *cycle* reversed-part :end1 2 :end2 2)) ;; sets Lisp image spinning forever
CL-USER> (let ((reversed-part (list 2 1)))
(setf (subseq *cycle* 0 2) reversed-part)) ;; sets Lisp image spinning forever
As said in comments, most functions that work on lists expect proper lists. Improper lists like circular ones might lead to infinite loops, or any other bad behavior.
You should better use explicit loops.
However, mapping functions like mapcar, maplist, ... must work with lists of different sizes (they end when the shortest one ends), so as long as one of the arguments is proper, you can generally expect the mapping to end (there is however still no guarantee). Likewise, subseq is likely to terminate if :end is provided:
;; IMPORTANT
(setf *print-circle* t)
(defun nrevplace (list start end)
(mapl (lambda (u v) (setf (car u) (car v)))
(nthcdr start list)
(nreverse (subseq list start end))))
(let ((list (list 1 2 3 :a :b :c 4)))
(setf list (nconc list list))
(nrevplace list 3 6)
list)
#1=(1 2 3 :C :B :A 4 . #1#)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With