dsm:这里的代码有一些奇怪的地方。注意
(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在这里展示的函数“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)))
希望有帮助!