Percursos
/
Clojure
Clojure
/
Exercícios
/
Transformação de coordenadas
Transformação de coordenadas

Transformação de coordenadas

Exercício de aprendizagem

Introdução

As closures são um padrão de programação em Clojure que permite usar variáveis de um âmbito lexical exterior dentro de uma função. O Clojure suporta closures de forma transparente, e muitas vezes usam-se sem se saber o que são.

;; 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))

Closures para guardar estado e passar valores

Usar um atom permite preservar algum estado:

;; 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))))

Cada chamada sucessiva a increment incrementa o seu contador:

(increment)
;;=> 1
(increment)
;;=> 2

Instruções

A tua empresa de design tem trabalhado sobretudo com transformações de CSS para construir páginas web. Depois de alguma discussão, decidiu-se começar a usar Clojure para fazer alguns cálculos de forma dinâmica. Alguns dos teus colegas de equipa têm menos experiência com Clojure, por isso decides usar um closure para criar transformações reutilizáveis para pares de coordenadas {x, y}.

1. Translada as coordenadas

Implementa a função translate2d que devolve uma função que usa um closure para fazer uma translação 2d repetível de um par de coordenadas.

(def move-coordinates-right-2px (translate2d 2 0))
(def result (move-coordinates-right-2px 4 8))
;; result => [6 8]

2. Escala as coordenadas

Implementa a função scale2d que devolve uma função que usa um closure para fazer uma escala 2d repetível de um par de coordenadas.

Neste exercício, assume apenas valores de escala positivos.

(def double-scale (scale2d 2 2))
(def result (double-scale 6 -3))
;; result => [12 -6]

3. Compõe funções de transformação

Combina duas funções de transformação para fazer uma transformação repetível. A isto chama-se muitas vezes composição de funções, em que o resultado da primeira função 'f(x)' é usado como valor de entrada da segunda função '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]

4. Guarda os resultados das funções

Implementa a função memoize-transform. Recebe uma função para memorizar e devolve uma nova função que se lembra dos parâmetros de entrada da função fornecida, para que o último valor devolvido possa ser "memorizado" e só seja calculado uma vez, caso a função seja chamada de novo com os mesmos argumentos.

A memorização é por vezes chamada de programação dinâmica: permite que operações dispendiosas sejam feitas apenas uma vez, uma vez que o seu resultado fica memorizado.

(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
Editar via GitHub A ligação abre numa nova janela ou separador
Clojure Exercism

Estás pronto para começar Transformação de coordenadas?

Inscreve-te no Exercism para aprenderes e dominares Clojure com 12 conceitos105 exercícios, e mentoria humana real, tudo grátis.