Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace this loop (circular list)

Tags:

common-lisp

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
like image 635
engineerX Avatar asked Jun 07 '26 19:06

engineerX


1 Answers

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#)
like image 121
coredump Avatar answered Jun 10 '26 09:06

coredump