È corretto usare il linguaggio backtick/virgola all'interno di un (loop…)?

StackOverflow https://stackoverflow.com/questions/101487

  •  01-07-2019
  •  | 
  •  

Domanda

Ho del codice che raccoglie punti (interi consensati) da un ciclo che assomiglia a questo:

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

La mia domanda è: è corretto da usare `(,x . ,y) in questa situazione?

Modificare:Questo esempio non riguarda la generazione di una tabella di 100x100 elementi, il codice qui illustra semplicemente l'uso di due variabili di ciclo e la sintesi dei relativi valori.Ho modificato il loop per renderlo chiaro.Il ciclo effettivo che utilizzo dipende da molte altre funzioni (e fa parte di una stessa funzione), quindi aveva più senso sostituire le chiamate con numeri interi letterali ed estrarre il ciclo dalla funzione.

È stato utile?

Soluzione

Sarebbe molto "meglio" fare semplicemente (contro x y).

Ma a rispondi alla domanda, non c'è niente di sbagliato nel farlo :) (a parte renderlo un po' più lento).

Altri suggerimenti

Penso che la risposta qui sia l'utilizzo delle risorse (a seguito di Questo post)

ad esempio nella clip:

[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:ci sono un paio di cose strane nel tuo codice Qui.Notare che

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

che probabilmente non è proprio quello che volevi.Nota tre cose:Innanzitutto, per come l'hai scritto, xey hanno lo stesso ruolo.Probabilmente volevi nidificare i loop.In secondo luogo, quello che fai dopo la y non è corretto, poiché non c'è un modulo lisp che lo segue.In terzo luogo, hai ragione nel dire che potresti utilizzare l'approccio backtick qui, ma rende il tuo codice più difficile da leggere e non idiomatico senza alcun guadagno, quindi è meglio evitarlo.

Indovinando cosa intendevi effettivamente, potresti fare qualcosa del genere (usando loop):

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

Se non ti piace la macro loop (come Kyle), puoi usare un altro costrutto di iterazione come

(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 ti ritrovi a fare spesso questo genere di cose, probabilmente dovresti scrivere una funzione più generale per incrociare le liste, quindi passarle queste liste di numeri interi

Se hai davvero un problema con l'iterazione, non solo con il ciclo, puoi fare questo genere di cose in modo ricorsivo (ma nota, questo non è uno schema, la tua implementazione potrebbe non garantire il TCO).La funzione "genint" mostrata da Kyle Qui è una variante di una funzione comune (ma non standard) iota.Tuttavia, aggiungere all'elenco è una cattiva idea.Un'implementazione equivalente come questa:

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

dovrebbe essere molto più efficiente, ma non è ancora una chiamata in coda.Nota: l'ho impostato per il più consueto basato su 0, ma ti ho dato un parametro facoltativo per iniziare da 1 o qualsiasi altro numero intero.Naturalmente quanto sopra può essere scritto in questo modo:

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

Il che ha il vantaggio di non far saltare la pila per grandi discussioni.Se la tua implementazione supporta l'eliminazione delle chiamate in coda, puoi anche evitare che la ricorsione vada fuori posto facendo qualcosa del genere:

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

Spero che aiuti!

Perché non solo

(cons x y)

A proposito, ho provato a eseguire il tuo codice in CLISP e non ha funzionato come previsto.Dato che non sono un grande fan della macro loop, ecco come potresti ottenere la stessa cosa in modo ricorsivo:

(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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top