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). Функция "genint", показанная Kyle здесь , является вариантом обычной (но не стандартной) функции йота. Однако добавление в список - плохая идея. Эквивалентная реализация, подобная этой:
(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)))
Надеюсь, это поможет!