附加到"循环收集"的结果在Lisp

时间:2015-04-26 23:13:44

标签: loops lisp common-lisp

我们说我运行以下

(loop for i to 4 collect i)

然后我得到一个列表(0 1 2 3 4)。现在,如果我想在结果中附加某些内容,我可以在其rplacd元素上使用last,但由于Lisp列表是链接列表,因此效率不高。这里的列表非常小,但它只是一个例子。

但是,由于循环工具按递增顺序返回列表,因此必须跟踪指向最后一个元素的指针,并使用rplacd或等效的结果更新结果。 macroexpand-all显示了CCL的作用,也可能是其他lisps。

问题:有没有办法使用这个"指针"在finally条款中?它允许一个人在结果上附加一些东西,这有时是有用的。

当然,编写指针机制很容易,但它并不那么好。例如,以下内容会将列表e附加到列表(0 1 ... n)

(defun foo (n e)
    (let* ((a (list nil)) (tail a))
        (loop for i to n
              do (rplacd tail (setf tail (list i)))
              finally (rplacd tail (setf tail e))
              (return (cdr a)))))

2 个答案:

答案 0 :(得分:7)

每次迭代和一次额外迭代的额外比较为您提供:

CL-USER 2 > (defun foo (n e &aux (z (1+ n)))
              (loop for i to z
                    unless (= i z)
                      collect i
                    else
                      nconc e))
FOO

CL-USER 3 > (foo 4 '(f o o))
(0 1 2 3 4 F O O)

答案 1 :(得分:4)

  

问题:有没有办法使用这个"指针"在finally子句中?它允许一个人在结果上附加一些东西,也就是说   有时很有用。

我认为答案是"没有"。 finally子句的语法在:

中给出
java -classpath C:\...\Metro\seaglasslookandfeel-0.2.jar;. Metro

当然,您可以将收集到某个特定变量中,然后附加或者使用nconc:

initial-final::= initially compound-form+ | finally compound-form+ 

这确实涉及额外的结果,但这可能是不可取的。 (我认为这是你想要避免的。)

另一个选择是使用 nconc 而不是收集来构建列表。如果您正在使用收集,那么您只需一次获取一个值然后再收集它。你可以将这一个值放入一个列表中,然后"收集"它与 nconc 。如果将一个元素列表保存到循环中的变量中,则可以引用它,它几乎就是尾指针。 E.g:

CL-USER> (loop for i from 1 to 5
              collect i into ns
              finally (return (nconc ns (list 'a 'b 'c))))
;=> (1 2 3 4 5 A B C)

在标有***的行中,对 nconc 的调用只需要遍历 ilist 的最终值,即(5)。这是一个非常快速的 nconc 电话。