Le closure sono un pattern di programmazione in Clojure che permette di usare all'interno di una funzione le variabili di uno scope lessicale esterno. Clojure supporta le closure in modo trasparente e spesso vengono usate senza sapere cosa siano.
;; Top-level definitions are global-scope
(def dozen 12)
;; Functions create a new scope.
;; Referencing the outer variable here is a closure.
(fn [n] (* dozen n))
Usare un atom permette di conservare parte dello stato:
;; This function closure increments the counter's state
;; in the outer lexical context.
;; This way the counter can be shared between many calling contexts.
(def increment
(let [counter (atom 0)]
(fn [] (swap! counter inc))))
Ogni chiamata successiva a increment incrementa il suo contatore:
(increment)
;;=> 1
(increment)
;;=> 2
La tua azienda di design ha lavorato principalmente con trasformazioni CSS per costruire pagine web. Dopo qualche discussione, si è deciso di iniziare a usare Clojure per eseguire alcuni calcoli in modo dinamico. Alcuni dei tuoi colleghi hanno meno esperienza con Clojure, quindi decidi di usare una closure per creare trasformazioni riutilizzabili per coppie di coordinate {x, y}.
Implementa la funzione translate2d che restituisce una funzione che fa uso di una closure per eseguire una traslazione 2d ripetibile di una coppia di coordinate.
(def move-coordinates-right-2px (translate2d 2 0))
(def result (move-coordinates-right-2px 4 8))
;; result => [6 8]
Implementa la funzione scale2d che restituisce una funzione che fa uso di una closure per eseguire una scalatura 2d ripetibile di una coppia di coordinate.
Per questo esercizio, supponi che i valori di scalatura siano solo positivi.
(def double-scale (scale2d 2 2))
(def result (double-scale 6 -3))
;; result => [12 -6]
Combina due funzioni di trasformazione per eseguire una trasformazione ripetibile. Questa operazione è spesso chiamata composizione di funzioni, dove il risultato della prima funzione 'f(x)' viene usato come input della seconda funzione 'g(x)'.
(def move-coordinates-right-2px (translate2d 2 0))
(def double-coordinates (scale2d 2 2))
(def composed-transformations
(compose-transform move-coordinates-right-2px
double-coordinates))
(def result (composed-transformations 0 1))
;; result => [4 2]
Implementa la funzione memoize-transform. Prende una funzione da memoizzare, poi restituisce una nuova funzione che ricorda gli input della funzione fornita, così che l'ultimo valore restituito possa essere «ricordato» e calcolato una sola volta se viene chiamata di nuovo con gli stessi argomenti.
La memoizzazione è talvolta chiamata programmazione dinamica: permette di eseguire operazioni costose una sola volta, dato che il loro risultato viene ricordato.
(def triple-scale (scale2d 3 3))
(def memoized-scale (memoize-transform triple-scale))
(memoized-scale 4 3)
;; => [12, 9], this is computed since it hasn't been computed before for the arguments
(memoized-scale 4 3)
;; => [12, 9], this is remembered, since it was computed already
Iscriviti a Exercism per imparare e padroneggiare Clojure con 12 concetti105 esercizi e il mentoring di persone reali, tutto gratis.