Understanding Cycle Macro Extensions

I expanded the macro below to see how it works, and got a little confused.

(loop for i below 4 collect i) 

expands to (I cleaned it a bit for readability)

 (block nil (let ((i 0)) (declare (type (and number real) i)) (let* ((list-head (list nil)) (list-tail list-head)) (tagbody sb-loop::next-loop (when (>= i 4) (go sb-loop::end-loop)) (rplacd list-tail (setq list-tail (list i))) (setq i (1+ i)) (print "-------") ;; added so I could see the lists grow (print list-head) (print list-tail) (print "-------") (go sb-loop::next-loop) sb-loop::end-loop (return-from nil (cdr list-head)))))) 

.. and here is the result of the work above.

 ;; "-------" ;; (NIL 0) ;; (0) ;; "-------" ;; "-------" ;; (NIL 0 1) ;; (1) ;; "-------" ;; "-------" ;; (NIL 0 1 2) ;; (2) ;; "-------" ;; "-------" ;; (NIL 0 1 2 3) ;; (3) ;; "-------" 

I just don’t see where the list is changed, I have to assume that the head and tail are eq , and thus a modification of one of them has changed the other, but someone can break what is happening on the rplacd line

+5
source share
1 answer

list-head and list-tail are initially the same (in the sense of eq ). list-head is the minus, which cdr is a list. list-tail indicates the last cons in the list (except initially, see below).

To add an item to the end of the list, replacd modifies the cdr list-tail to add new cons, and list-tail updated to indicate new flaws.

When the loop ends, the result is cdr list-head .

Why is this complex business with additional disadvantages? Since the algorithm for adding a list is simplified when list-tail always a pointer to the last cons of the list. But first, an empty list has no flaws. So the trick is to make the list longer.

+9
source

Source: https://habr.com/ru/post/1207018/


All Articles