2008-09-19 1 views
1

J'ai un code qui collecte des points (entiers) CONSED d'une boucle qui ressemble à quelque chose comme ceci:Est-il correct d'utiliser l'idiome backtick/virgule à l'intérieur d'un (boucle ...)?

(loop 
    for x from 1 to  100 
    for y from 100 downto 1 
     collect `(,x . ,y)) 

Ma question est, est-il correct d'utiliser `(,x . ,y) dans cette situation? Editer: Cet exemple ne concerne pas la génération d'une table de 100x100 éléments, le code ici illustrent juste l'utilisation de deux variables de boucle et l'imposition de leurs valeurs. J'ai édité la boucle pour que cela soit clair. La boucle que j'utilise dépend de plusieurs autres fonctions (et en fait partie), il est donc plus logique de remplacer les appels par des entiers littéraux et de sortir la boucle de la fonction.

+0

FYI, il suffit de laisser de côté le DO et son ANSI CL conforme. :) (DO est pour l'exécution des expressions Lisp, pas pour l'introduction de clauses LOOP.) –

+0

Merci pour la correction – dsm

+0

Vous êtes sûr de l'avoir fait? Je l'ai couru avec les deux boucles de 0 à 5 et j'ai obtenu ((0. 0) (1 .1) (2 .2) (3. 3) (4. 4) (5. 5)), ce que je ne fais pas. pense était le résultat souhaité. –

Répondre

7

Il serait beaucoup « mieux » pour le faire (contre x y).

Mais à répondre à la question, il n'y a rien de mal à le faire :) (sauf le faire un peu plus lent).

1

Pourquoi ne pas simplement

(cons x y) 

Soit dit en passant, j'ai essayé d'exécuter votre code dans CLISP et il ne fonctionne pas comme prévu. Depuis que je ne suis pas un grand fan de la macro boucle est ici comment vous pouvez accomplir la même chose récursive:

(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) 
+0

Battez-moi par 9 secondes, oh pourquoi ai-je dû élaborer? ; o) – leppie

+0

Le code était juste un exemple, j'ai un code plus «intelligent» qui détermine ce que recherche la boucle, pas une table. – dsm

+0

Oh, je ne savais pas si vous demandiez parce que votre code était cassé. –

5

Je pense que la réponse est ici l'utilisation des ressources (à la suite de This post)

par exemple dans 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]> 
3

dsm: il y a deux ou trois choses bizarres à propos de votre code here. Notez que

(loop for x from 1 to 100000 
    for y from 1 to 100000 do 
    collect `(,x . ,y)) 

équivaut à:

(loop for x from 1 to 100 
    collecting (cons x x)) 

qui est probablement pas tout à fait ce que vous vouliez. Notez trois choses: Premièrement, comme vous l'avez écrit, x et y ont le même rôle. Vous avez probablement voulu nicher des boucles. Deuxièmement, votre faire après le y est incorrect, car il n'y a pas de forme lisp qui le suit. Troisièmement, vous avez raison de dire que vous pouvez utiliser l'approche backtick ici, mais cela rend votre code plus difficile à lire et n'est pas idiomatique pour aucun gain, donc mieux vaut l'éviter.

Deviner ce que vous avez réellement l'intention, vous pourriez faire quelque chose comme ça (boucle en utilisant):

(loop for x from 1 to 100 appending 
    (loop for y from 1 to 100 collecting (cons x y))) 

Si vous n'aimez pas la macro boucle (comme Kyle), vous pouvez utiliser une autre itération construire comme

(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)) 

Si vous vous trouvez faire ce genre de chose beaucoup, vous devriez probablement écrire une fonction plus générale pour les listes de traverser, passer ensuite ces listes d'entiers

Si vous avez vraiment un problème avec l'itération, pas seulement en boucle, vous pouvez faire ce genre de chose récursivement (mais notez que ce n'est pas un schéma, votre implémentation peut ne pas garantir le TCO). La fonction "genint" montrée par Kyle here est une variante d'une fonction commune (mais pas standard) iota.Cependant, l'ajout à la liste est une mauvaise idée. Une implémentation équivalente comme ceci:

(defun iota (n &optional (start 0)) 
    (let ((end (+ n start))) 
    (labels ((next (n) 
       (when (< n end) 
       (cons n (next (1+ n)))))) 
     (next start)))) 

devrait être beaucoup plus efficace, mais n'est toujours pas un appel de queue. Note J'ai configuré ceci pour la base 0 la plus habituelle, mais vous donne un paramètre optionnel pour commencer à 1 ou tout autre entier. Bien sûr, le ci-dessus peut être écrit quelque chose comme:

(defun iota (n &optional (start 0)) 
    (loop repeat n 
    for i from start collecting i)) 

qui a l'avantage de ne pas souffler la pile pour les grands arguments. Si votre implémentation prend en charge l'élimination des appels de queue, vous pouvez également éviter la récursion en cours d'exécution sur place en faisant quelque chose comme ceci:

(defun iota (n &optional (start 0)) 
    (labels ((next (i list) 
      (if (>= i (+ n start)) 
       nil 
       (next (1+ i) (cons i list))))) 
    (next start nil))) 

Hope that helps!

+0

Vous avez raison, il existe des moyens plus efficaces d'accomplir ce que je faisais. J'essayais de dupliquer ce que je pensais être la sortie prévue du script le plus rapidement possible. Je ne suis pas un utilisateur de CL (je suis un Schemer), donc je ne savais pas si CL avait des fonctions de création de listes de numéros, alors merci pour le conseil –

+0

Ceci est une excellente réponse! – jfm3

+0

Ceci est en effet une bonne réponse, mais comme je l'ai noté, la boucle cassée était juste une illustration. J'ai maintenant édité la question pour mieux refléter l'intention de la boucle (consing des variables, plutôt que de générer une table). Merci pour votre réponse. – dsm

Questions connexes