了解循环宏扩展

Bag*_*ers 5 macros loops common-lisp

我扩展了下面的宏,看看它是如何工作的,发现自己有点困惑.

(loop for i below 4 collect i)
Run Code Online (Sandbox Code Playgroud)

扩展到(为了便于阅读,我已经清理了一点)

(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))))))
Run Code Online (Sandbox Code Playgroud)

..这里是运行上面的输出..

;; "-------" 
;; (NIL 0) 
;; (0) 
;; "-------" 
;; "-------" 
;; (NIL 0 1) 
;; (1) 
;; "-------" 
;; "-------" 
;; (NIL 0 1 2) 
;; (2) 
;; "-------" 
;; "-------" 
;; (NIL 0 1 2 3) 
;; (3) 
;; "-------"
Run Code Online (Sandbox Code Playgroud)

我只是看不到列表头被修改的位置,我必须假设头部和尾部都是eq,因此修改一个正在修改另一个但是有人可以请分解rplacd线上发生的事情吗?

Lar*_*off 9

list-head并且list-tail最初是相同的(在eq某种意义上). list-head是一个缺点,其中cdr是收集的列表. list-tail指向列表中的最后一个缺点(最初除外,见下文).

要将一个元素添加到列表的末尾,replacd修改cdr list-tail以添加新的缺点,并list-tail更新为指向新的缺点.

当循环终止时,结果是cdr list-head.

为什么这个复杂的业务有额外的缺点?因为列表附加算法变得更容易,因为list-tail它始终是指向列表最后一个缺点的指针.但是在开始时,空列表没有缺点.所以诀窍是让列表更长一点.