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.

Foi útil?

Solução

Seria muito 'melhor' apenas para fazer (cons x y).

Mas a responder à pergunta , 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)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top