2010-06-21 22 views
11

Come posso valutare un elenco di funzioni (impure) in Clojure? Per esempio:Come valutare una sequenza di funzioni impure in Clojure?

[#(println "1") #(println "2") #(println "3")] 

Il risultato atteso è:

1 
2 
3 

C'è un modo per raggiungere questo obiettivo senza utilizzare le macro? Qualcosa come (map evaluate fns-seq), forse?

(Ho bisogno di questo per il disegno alcuni elementi grafici utilizzando l'API Clojure.processing.)

risposta

17
user> (let [fs [#(println "1") #(println "2") #(println "3")]] 
     (doseq [f fs] (f))) 
1 
2 
3 
nil 
+0

Grande, che ha funzionato . Molte grazie! –

5

Ciò avidamente consumare tutta la ss, chiamando tutte le funzioni per gli effetti collaterali e la restituzione qualunque sia l'ultimo ritorna:

(reduce #(%2) nil [#(println :foo) #(println :bar)]) 
; => prints :foo, then :bar, then returns nil 

Se si desidera tenere sui valori di ritorno, è possibile utilizzare reductions invece:

(reductions #(%2) nil [#(println :foo) #(println :bar)]) 
; => prints :foo, then :bar, then returns (nil nil) 

reductions si trova in clojure.contrib.seq-utils in Clojure 1.1 e in clojure.core nelle istantanee attuali di 1.2.

Aggiornamento: noti che reductions restituisce un ss pigro, quindi non c'è miglioramento rispetto map (. NB in ​​map che ci si vuole utilizzare #(%) piuttosto che #(%2)). L'ho menzionato qui principalmente per completezza. In effetti, ho pubblicato l'intera risposta per completezza, perché normalmente andavo con l'approccio doseq (vedi la risposta di Brian).

+0

Grazie per i vostri commenti aggiuntivi. Posso immaginare che il mio "problema" si insinuerà più spesso quando si tratta di librerie dal mondo imperativo di Java. Forse una macro (dofns fns) sarebbe una bella astrazione, che al momento manca in Clojure. –

1

(apply pcalls [#(println "1") #(println "2") #(println "3")]) fa proprio questo. Basta stare attenti al parallelismo di pcalls (quindi alla mancanza di sequenzialità) e alla pigrizia.

+0

È bello sapere i pcalls :) – nXqd

0

Una vecchia domanda, lo so, ma c'è un'altra opzione. si può semplicemente invoke le funzioni:

(defn generate-fns [] 
    [#(println "1") #(println "2") #(println "3")]) 

(dorun (pmap (memfn invoke) (generate-fns))) 

Questo consente di decidere in un contesto diverso come si vorrebbe per eseguire le funzioni (ad esempio, pmap, o claypoole'supmap per esempio)

Problemi correlati