2010-02-22 14 views
28

Ho una sequenza (foundApps) restituita da una funzione e voglio mappare una funzione a tutti i suoi elementi. Per qualche ragione, apply e count lavoro per il sequnece ma map non lo fa:Clojure apply vs map

(apply println foundApps) 
(map println rest foundApps) 
(map (fn [app] (println app)) foundApps) 
(println (str "Found " (count foundApps) " apps to delete")))) 

Stampe:

{:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(2)>} {:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(4)>} 
Found 2 apps to delete for id 1235 

Così apply sembra funzionare felicemente per la sequenza, ma map non lo fa. Dove sono stupido?

risposta

31

Molto probabilmente sei colpito dalla pigrizia di map. (map produce una sequenza pigra che si realizza solo quando un codice utilizza effettivamente i suoi elementi e anche in questo caso la realizzazione avviene in blocchi, così devi camminare per tutta la sequenza per assicurarti che tutto sia realizzato.) Prova a racchiudere l'espressione map in un dorun:

(dorun (map println foundApps)) 

Inoltre, dal momento che si sta facendo solo per gli effetti collaterali, potrebbe essere più pulito di utilizzare doseq invece:

(doseq [fa foundApps] 
    (println fa)) 

Nota che (map println foundApps) dovrebbe funzionare bene al REPL; Suppongo che tu l'abbia estratto da qualche parte nel tuo codice dove non è forzato. Non c'è una tale differenza con doseq che è rigoroso (cioè non pigro) e porterà le sequenze di argomenti per te in nessuna circostanza. Si noti inoltre che doseq restituisce nil come valore; è solo un bene per gli effetti collaterali. Finalmente ho saltato il rest dal tuo codice; potresti aver inteso (rest foundApps) (a meno che non sia solo un refuso).

Si noti inoltre che (apply println foundApps) stampa tutte le foundApps su una riga, mentre (dorun (map println foundApps)) stamperà ogni membro del foundApps sulla propria riga.

+3

c'è una differenza tra 'dorun' e' doall'? –

8

Una piccola spiegazione potrebbe aiutare. In generale si usa apply per splatare una sequenza di elementi in un insieme di argomenti a una funzione. Quindi applicare una funzione ad alcuni argomenti significa semplicemente passarli come argomenti alla funzione, in una singola chiamata di funzione.

La funzione mappa farà ciò che si desidera, crea un nuovo seq inserendo ciascun elemento dell'ingresso in una funzione e quindi memorizzando l'output. Lo fa pigramente, quindi, i valori verranno calcolati solo quando si esegue l'iterazione sull'elenco. Per forzare questo è possibile utilizzare la funzione (doall my-seq), ma la maggior parte delle volte non è necessario farlo.

Se è necessario eseguire un'operazione immediatamente perché ha effetti collaterali, come la stampa o il salvataggio in un database o qualcosa del genere, in genere si usa doseq.

Quindi, per aggiungere "pippo" per tutte le applicazioni (ammesso che sono stringhe):

(mappa (fn [App] (str app "pippo"))-apps trovati)

o utilizzando lo shorhand per una funzione anonima:

(mappa # (str% "pippo") trovati-apps)

Fare la stessa, ma la stampa immediatamente può essere fatto con uno di questi:

(DOALL (Mappa # (% println) trovati-apps))

(doseq [app trovati-apps] (println app))

13

Ho una spiegazione semplice che manca in questo post. Immaginiamo una funzione astratta F e un vettore. Così,

(apply F [1 2 3 4 5]) 

traduce

(F 1 2 3 4 5) 

che significa che F deve essere al migliore dei casi variadic.

Mentre

(map F [1 2 3 4 5]) 

traduce

[(F 1) (F 2) (F 3) (F 4) (F 5)] 

che significa che F deve essere variabile singola, o almeno si comportano in questo modo.

Ci sono alcune sfumature sui tipi, dal momento che map restituisce effettivamente una sequenza pigra anziché vettoriale. Ma per semplicità, spero che sia perdonabile.

+0

Grazie per la semplice risposta concettuale! – JaKXz

+3

Ottima spiegazione di applicare vs mappa. C'è un nome per ciò che si applica in alcuni altri linguaggi di programmazione dinamica, si chiama splatting o unpacking. – blushrt

+0

La mia vita è più semplice ora. Grazie (: – stryku