2012-08-13 4 views
5

Sto ancora imparando questo paradigma funzionale alieno ...Come dovrei creare un elenco e restituirlo in clojure?

Come scriverei il seguente codice in Clojure e in modo funzionale? si assume che queste parti mancanti siano definite altrove e si comportino come descritto nei commenti. Eccolo in Python, che mi è familiare.

usernames = [] 
# just the usernames of all the connections I want to open. 
cancelfunctions = {} 
# this global contains anonymous functions to cancel connections, keyed by username 

def cancelAll(): 
    for cancel in cancelfunctions.values(): 
     cancel() 

def reopenAll(): 
    cancelfunctions = {} 
    for name in usernames: 
     # should return a function to close the connection and put it in the dict. 
     cancelfunctions[name] = openConnection() 

Tutto quello che ho davvero bisogno di sapere è come costruire una nuova dict di callback, come nella funzione reopenAll, ma sto tra cui alcuni più contesto qui perché è probabile che sto commettendo un qualche tipo di funzionalità paradigma atrocità, e molto probabilmente vorrai risolvere l'intero programma. :)

+0

So che probabilmente non è appropriato, ma non ho potuto resistere alla condivisione quando ho visto il tuo riferimento al "[paradigma funzionale alieno] (http://landoflisp.com/#guilds)". – DaoWen

risposta

6

Costruire strutture dati in Clojure spesso coinvolge reduce, che alimenta una sequenza di ingressi a una funzione che accumula un valore di ritorno finale. Ecco due modi per scrivere una funzione che costruisce una mappa (cioè il dizionario) del nome utente per il valore restituito di open-connection.

;; Using reduce directly 
(defn reopen-all [usernames] 
    (reduce 
    (fn [m name] (assoc m name (open-connection))) 
    {} usernames)) 

;; Using into, which uses reduce under the hood 
(defn reopen-all [usernames] 
    (into {} (for [name usernames] 
      [name (open-connection)]))) 

Si noti che queste due funzioni restituiscono un valore e non mutano lo stato globale, come fa il codice Python. Lo stato globale non è intrinsecamente cattivo, ma è bene separare la generazione di valore dalla manipolazione dello stato. Per lo stato, probabilmente si vorrà un atom:

(def usernames [...]) 
(def cancel-fns (atom nil)) 

(defn init [] 
    (reset! cancel-fns (reopen-all usernames))) 

Ed ecco cancel-all per completezza:

(defn cancel-all [] 
    (doseq [cancel-fn (vals @canel-fns)] 
    (cancel-fn))) 
+0

Grazie, questa è un'ottima risposta! – user1552512

2

Ecco un approccio funzionale in python:

def reopen(usernames): 
    return dict((name, openConnection()) for name in usernames) 

Si possono trovare è più facile "tradurre" in uno stile funzionale in python prima di tentare di usare un linguaggio principalmente funzionale.