我有一些代码从循环中收集点(consed integers),看起来像这样:
(loop
for x from 1 to 100
for y from 100 downto 1
collect `(,x . ,y))
我的问题是,在这种情况下使用`(,x . ,y)
是否正确?
编辑:此示例不是关于生成100x100项的表,这里的代码只是说明了两个循环变量的使用以及它们的值的消耗。我编辑了循环以使其清楚。我使用的实际循环取决于其他几个函数(并且是其自身的一部分),因此用文字整数替换调用并将循环拉出函数更有意义。
答案 0 :(得分:7)
这样做会更好(cons x y)。
但是回答问题,这样做没有错:)(除了让它慢一点)。
答案 1 :(得分:5)
我认为这里的答案是资源利用率(来自This post)
例如在clisp中:
[1]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect (cons x y))
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.469 sec.
Run time: 0.468 sec.
Space: 1609084 Bytes
GC: 1, GC time: 0.015 sec.
NIL
[2]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y)) ;`
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.969 sec.
Run time: 0.969 sec.
Space: 10409084 Bytes
GC: 15, GC time: 0.172 sec.
NIL
[3]>
答案 2 :(得分:3)
dsm:您的代码here有一些奇怪的事情。注意
(loop for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y))
相当于:
(loop for x from 1 to 100
collecting (cons x x))
这可能不是你想要的。注意三件事:首先,你写它的方式,x和y有相同的作用。你可能想要嵌套循环。第二,你在y之后做的不正确,因为它之后没有lisp形式。第三,你是正确的,你可以在这里使用反引号方法,但它使你的代码更难阅读,而不是惯用,没有收益,所以最好避免。
猜测你的意图,你可能会做这样的事情(使用循环):
(loop for x from 1 to 100 appending
(loop for y from 1 to 100 collecting (cons x y)))
如果您不喜欢循环宏(如Kyle),您可以使用其他迭代构造,如
(let ((list nil))
(dotimes (n 100) ;; 0 based count, you will have to add 1 to get 1 .. 100
(dotimes (m 100)
(push (cons n m) list)))
(nreverse list))
如果你发现自己做了很多这样的事情,你应该为跨越列表编写一个更通用的函数,然后将这些整数列表传递给它
如果你真的遇到迭代问题,而不仅仅是循环,你可以递归地做这种事情(但请注意,这不是方案,你的实现可能无法保证TCO)。 Kyle here显示的函数“genint”是常见(但不是标准)函数iota的变体。但是,附加到列表是一个坏主意。像这样的等效实现:
(defun iota (n &optional (start 0))
(let ((end (+ n start)))
(labels ((next (n)
(when (< n end)
(cons n (next (1+ n))))))
(next start))))
应该更有效率,但仍然不是尾部调用。注意我已经设置了更常用的基于0的,但给你一个可选的参数从1开始或任何其他整数。当然,上面的内容可以写成:
(defun iota (n &optional (start 0))
(loop repeat n
for i from start collecting i))
其优点是不会为大型参数吹掉堆栈。如果您的实现支持尾调用消除,您还可以通过执行以下操作来避免递归失败:
(defun iota (n &optional (start 0))
(labels ((next (i list)
(if (>= i (+ n start))
nil
(next (1+ i) (cons i list)))))
(next start nil)))
希望有所帮助!
答案 3 :(得分:1)
为什么不
(cons x y)
顺便说一下,我试图在CLISP中运行你的代码并且它没有按预期工作。由于我不是循环宏的忠实粉丝,所以你可以递归地完成同样的事情:
(defun genint (stop)
(if (= stop 1) '(1)
(append (genint (- stop 1)) (list stop))))
(defun genpairs (x y)
(let ((row (mapcar #'(lambda (y)
(cons x y))
(genint y))))
(if (= x 0) row
(append (genpairs (- x 1) y)
row))))
(genpairs 100 100)