2013-02-14 10 views
15

l'altro giorno stavo cercando di trovare un esempio di chiusura in Clojure. Mi sono inventato ed esempio che avevo visto prima e ho pensato che fosse appropriato.Chiusura Clojure

Ahimè, mi è stato detto che non era un buono e che dovrei fornire qualcosa con let.

Qualcuno può far luce?

(defn pow [x n] (apply * (repeat x n))) 
(defn sq [y] (pow y 2)) 
(defn qb [y] (pow y 3)) 

risposta

20

Una chiusura è una funzione che ha accesso ad un certo valore/variabile denominata fuori proprio ambito, così da una portata maggiore in prossimità della funzione quando è stato creato (ciò esclude argomenti di funzione e valori denominati locali creati all'interno della funzione). I tuoi esempi non si qualificano, poiché ogni funzione utilizza solo valori denominati dai propri ambiti.

Esempio:

(def foo 
    (let [counter (atom 0)] 
    (fn [] (do (swap! counter inc) @counter)))) 

(foo) ;;=> 1 
(foo) ;;=> 2 
(foo) ;;=> 3, etc 

Ora foo è una funzione che restituisce il valore di un atomo che è fuori della sua portata. Poiché la funzione mantiene ancora un riferimento a quell'atomo, l'atomo non sarà raccolto in modo improprio purché sia ​​necessario foo.

14

Funzione che restituisce la funzione le funzioni di ordine superiore sono buoni esempi di chiusura.

(defn pow [n] 
    (fn [x] (apply * (repeat n x)))) 

(def sq (pow 2)) 
(def qb (pow 3)) 
+0

Ciao, quindi il mio esempio potrebbe essere una chiusura se mi aveva definito il corpo del mio pow come hai fatto tu (la chiusura è l'anon f)? – Eddy

+0

Sì, sarebbe un modo per descrivere la chiusura – Ankur

+0

+1 Esempio elegante! –

3

Un altro esempio di chiusura. Esistono due funzioni che condividono lo stesso ambiente (state).

(defn create-object [init-state] 
    (let [state (atom init-state)] 
    {:getter (fn [] 
       @state) 
    :setter (fn [new-val] 
       (reset! state new-val))})) 

(defn test-it [] 
    (let [{:keys [setter getter]} (create-object :init-value)] 
    (println (getter)) 
    (setter :new-value) 
    (println (getter)))) 

(test-it) 
=> :init-value 
    :new-value 
+1

grazie, un grande esempio!) – Eddy

-1

Volevo avere qualcosa che imposta valori costanti che devono essere utilizzati ogni volta.

(def myran 
    (let [constrand (rand)] 
    (fn [n] (* n constrand)))) 


(myran 3) 
2.7124521745892096 
(myran 1) 
0.9041507248630699 
(myran 3) 
2.7124521745892096 

Ciò imposterà solo un valore per "constrand" una volta. Questo è un esempio molto artificiosa, ma io volevo essere in grado di fare qualcosa di simile:

JavaScript: The Good Parts

Questo è da: JavaScript: The Good Parts