2012-04-02 23 views
22

mi piacerebbe implementare questo piccolo codice Clojure, ma sto lottando:Come implementare un ciclo For in Clojure

struct mystruct { 
    int id; 
    int price; 
}; 

mystruct mydata[10]; 

for (int i=0; i<10; i++) { 
    myfunction(mydata[i].id, mydata[i].price); 
    //other things... 
} 

Io sono un principiante con Clojure ed è davvero complicato per me di fare qualcosa semplice come questo, ma sto davvero cercando di imparare il più possibile, come so che ci sono grandi vantaggi con Clojure come l'utilizzo di arbitri ...

Vorrei davvero apprezzare se qualcuno mi potrebbe aiutare. Grazie!!

risposta

32

Un modo per tradurre un imperativo per il ciclo su Clojure consiste nell'utilizzare la macro for.

(for [i (range 10)] (inc i)) 

La funzione di cui sopra restituirà tutti i numeri da 0 a 9 incrementato di 1. Tuttavia, sembra si vuole semplicemente iterare su una collezione sequenziale e utilizzare ogni elemento. Se è tutto ciò di cui hai bisogno, non è necessario fare riferimento a un valore di indice, ma puoi fare riferimento a ciascun elemento direttamente.

(for [d my-vec-of-data] (my-function d)) 

Tuttavia, per questo semplice caso, la funzione map sarebbe probabilmente una scelta migliore perché è stato progettato per richiamare le funzioni con argomenti provenienti da collezioni. Il seguente esempio è equivalente all'uso di for in precedenza.

(map my-function my-vec-of-data) 

Sia map e for restituire un insieme di valori costituiti da valori restituiti dalla my-function. Questo perché le strutture dati di Clojure sono immutabili, quindi è necessario restituire una nuova collezione. Se questo non è ciò di cui hai bisogno o se la tua funzione ha effetti collaterali, puoi utilizzare doseq invece di for, che restituisce nil.

+2

fa 'i' incrementare automaticamente? – nuvio

+1

@nuvio: 'i' sarà l'elemento effettivo nella sequenza, non l'indice. E sì, la macro 'for' gestirà l'iterazione della sequenza per te. – Chuck

+0

"doseq" è ottimo per le funzioni in cui non è necessario un valore di ritorno poiché restituisce un singolo nil anziché 1 per elemento – jm0

30

La risposta di Jeremy è buona per come fare un ciclo for in Clojure idiomatico.

Se si vuole veramente uno stile imperativo per ciclo in Clojure, è possibile creare uno con questa macro:

(defmacro for-loop [[sym init check change :as params] & steps] 
`(loop [~sym ~init value# nil] 
    (if ~check 
     (let [new-value# (do [email protected])] 
     (recur ~change new-value#)) 
     value#))) 

Uso come segue:

(for-loop [i 0 (< i 10) (inc i)] 
    (println i)) 
+29

Mi piace come in Clojure se manchi una funzione linguistica, invece di aspettare che sia aggiunto a una versione futura, puoi semplicemente scrivere il tuo. – Dale