Les closures sont un modèle de programmation en Clojure qui permet d'utiliser des variables issues d'une portée lexicale externe à l'intérieur d'une fonction. Clojure prend en charge les closures de façon transparente, et on les utilise souvent sans savoir ce qu'elles sont.
;; 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))
Utiliser un atom permet de conserver un peu d'état :
;; 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))))
Chaque appel successif à increment incrémente son compteur :
(increment)
;;=> 1
(increment)
;;=> 2
Ton entreprise de design a surtout travaillé avec des transformations CSS pour construire des pages web. Après quelques discussions, il est décidé de commencer à utiliser Clojure pour effectuer certains calculs de façon dynamique. Certains de tes collègues connaissent moins bien Clojure, tu décides donc d'utiliser une fermeture de fonction pour créer des transformations réutilisables pour des paires de coordonnées {x, y}.
Implémente la fonction translate2d, qui renvoie une fonction utilisant une fermeture pour effectuer une translation 2D répétable d'une paire de coordonnées.
(def move-coordinates-right-2px (translate2d 2 0))
(def result (move-coordinates-right-2px 4 8))
;; result => [6 8]
Implémente la fonction scale2d, qui renvoie une fonction utilisant une fermeture pour mettre une paire de coordonnées à l'échelle de façon répétable.
Pour cet exercice, suppose que les valeurs de mise à l'échelle sont toujours positives.
(def double-scale (scale2d 2 2))
(def result (double-scale 6 -3))
;; result => [12 -6]
Combine deux fonctions de transformation pour effectuer une transformation répétable. On appelle souvent cela la composition de fonctions : le résultat de la première fonction 'f(x)' sert d'entrée à la seconde fonction '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]
Implémente la fonction memoize-transform. Elle prend une fonction à memoize, puis renvoie une nouvelle fonction qui se souvient des entrées de la fonction fournie, de sorte que la dernière valeur de retour puisse être « mémorisée » et ne soit calculée qu'une seule fois si on l'appelle à nouveau avec les mêmes arguments.
La mémorisation est parfois appelée programmation dynamique ; elle permet de n'effectuer qu'une seule fois des opérations coûteuses, puisque leur résultat est mémorisé.
(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
Inscris-toi sur Exercism pour apprendre et maîtriser Clojure avec 12 concepts105 exercices, et un vrai mentorat humain, le tout gratuitement.