É correto usar a crase / vírgula idioma dentro de um (circular ...)?
Pergunta
Eu tenho algum código que recolhe pontos (inteiros Consed) a partir de um circuito que é algo como isto:
(loop
for x from 1 to 100
for y from 100 downto 1
collect `(,x . ,y))
A minha pergunta é, é correto usar `(,x . ,y)
nesta situação?
Editar: Este exemplo não é sobre a geração de uma tabela de 100x100 itens, o código aqui apenas ilustrar o uso de duas variáveis ??de laço eo consing de seus valores. Eu editei o loop para deixar isso claro. A utilização efectiva ciclo I depende de várias outras funções (e é parte de um mesmo) por isso fez mais sentido para substituir as chamadas com números inteiros literais e puxe o laço fora da função.
Solução
Seria muito 'melhor' apenas para fazer (cons x y).
Mas a responder à pergunta ??strong>, não há nada de errado em fazer isso :) (exceto tornando-se um pouco mais lento).
Outras dicas
Eu acho que a resposta aqui é a utilização de recursos (seguinte a partir de Este post )
Por exemplo, em 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]>
dsm: há um par de coisas estranhas sobre o seu código de aqui . Note que
(loop for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y))
é equivalente a:
(loop for x from 1 to 100
collecting (cons x x))
que provavelmente não é o que você pretende. Observe três coisas: Em primeiro lugar, a forma como você escreveu isso, X e Y têm o mesmo papel. Você provavelmente significava a lacetes ninho. Em segundo lugar, o seu fazer depois do y é incorreto, como não há forma lisp que se lhe segue. Em terceiro lugar, você está certo de que você poderia usar a abordagem backtick aqui, mas ele faz o seu código mais difícil de ler e não idiomática para nenhum ganho, então melhor evitar.
Adivinhar o que você realmente a intenção, você pode fazer algo como isto (usando circular):
(loop for x from 1 to 100 appending
(loop for y from 1 to 100 collecting (cons x y)))
Se você não gosta da macro loop (como Kyle), você pode usar uma outra construção iteração como
(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))
Se você está fazendo esse tipo de coisa muito, você provavelmente deve escrever uma função mais geral para as listas de cruzamento, em seguida, passá-lo estas listas de inteiros
Se você realmente tem um problema com iteração, não apenas loop, você pode fazer esse tipo de coisa de forma recursiva (mas nota, esta não é esquema, a sua implementação pode não garantida TCO). A função "genint" mostrado por Kyle aqui é uma variante de um comum (mas não standard) função iota. No entanto, acrescentar à lista é uma má idéia. Uma implementação equivalente assim:
(defun iota (n &optional (start 0))
(let ((end (+ n start)))
(labels ((next (n)
(when (< n end)
(cons n (next (1+ n))))))
(next start))))
deve ser muito mais eficiente, mas ainda não é uma chamada de cauda. Nota que eu configurá-lo para o mais usual baseado em 0, mas deu-lhe um parâmetro opcional para iniciar em 1 ou qualquer outro inteiro. Claro que a coisa acima pode ser escrito como:
(defun iota (n &optional (start 0))
(loop repeat n
for i from start collecting i))
Que tem a vantagem de não soprando a pilha para grandes argumentos. Se sua implementação eliminação chamada suportes cauda, ??você também pode evitar a recursão funcionando fora do lugar, fazendo algo parecido com isto:
(defun iota (n &optional (start 0))
(labels ((next (i list)
(if (>= i (+ n start))
nil
(next (1+ i) (cons i list)))))
(next start nil)))
Espero que ajude!
Por que não apenas
(cons x y)
A propósito, eu tentei executar seu código em CLISP e não funcionou como esperado. Desde que eu não sou um grande fã do macro ciclo aqui está como você pode fazer a mesma coisa de forma recursiva:
(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)