97 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			97 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | --- | |||
|  | title: Clojure   Looprecur | |||
|  | localeTitle: Clojure Looprecur | |||
|  | --- | |||
|  | Você pode precisar entender [`if`](//forum.freecodecamp.com/t/clojure-conditionals/18412) e [`let`](//forum.freecodecamp.com/t/clojure-create-local-variables-with-let/18415) entender completamente a recursão no Clojure. | |||
|  | 
 | |||
|  | ## `for` e `while`
 | |||
|  | 
 | |||
|  | O Clojure não possui loops ou loops while. Isso faz sentido, se você pensar sobre isso. Um loop `for` altera uma variável e isso não é permitido no Clojure. | |||
|  | ``` | |||
|  | for (var i = 0; i < 10; i++) {  | |||
|  |   console.log(i);  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | `i++` significa que adicionamos um à variável `i` toda vez que o loop termina - um exemplo claro de uma variável sendo mutada. | |||
|  | 
 | |||
|  | `while` loops são menos dependentes de variáveis variáveis, mas são, da mesma forma que os loops. | |||
|  | ``` | |||
|  | var i = 0;  | |||
|  |  while (i < 10) {  | |||
|  |   console.log(i);  | |||
|  |   i++;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | `while` loops sempre tem uma condição, como `i < 10` , e vai quebrar se essa condição não for mais verdadeira. Isso significa que eles têm que ter algum tipo de efeito colateral (como adicionar 1 a `i` ) para que a condição seja eventualmente falsa; caso contrário, o loop duraria para sempre. | |||
|  | 
 | |||
|  | ## Recursão
 | |||
|  | 
 | |||
|  | Felizmente, o Clojure tem um loop de algum tipo. Esses loops usam recursão - uma função que chama a si mesma. O algoritmo recursivo mais simples é o de encontrar um fatorial numérico positivo (5 fatorial, por exemplo, igual a `5 * 4 * 3 * 2` ). | |||
|  | ``` | |||
|  | (defn fact [x]  | |||
|  |   (loop [nx prod 1] ;; this works just like a 'let' binding.  | |||
|  |     (if (= 1 n)  ;; this is the base case.  | |||
|  |       prod  | |||
|  |       (recur (dec n) (* prod n)))))  | |||
|  | ``` | |||
|  | 
 | |||
|  |  [IDEOne isso!](https://ideone.com/3iP3tI) | |||
|  | 
 | |||
|  | Você notará que `(loop [nx prod 1] ...)` é bastante semelhante a um `let` binding. Na verdade, funciona da mesma maneira - aqui, ligamos `n` para `x` e `prod` para 1. | |||
|  | 
 | |||
|  | Cada função recursiva tem um "caso base". Esta é a condição que faz com que o loop pare de fazer loop. Nesse caso, nosso loop pára se `n = 1` e retorna `prod` . Se `n` não for igual a 1, o loop se repetirá. | |||
|  | ``` | |||
|  | (recur (dec n) (* prod n))  | |||
|  | ``` | |||
|  | 
 | |||
|  | Essa função `recur` reinicia o loop, mas com ligações diferentes. Desta vez, `n` não está ligado a `x` , mas está ligado a `(dec n)` (o que significa `decrement n` ou `n - 1` ), e `prod` está ligado a `(* prod n)` . | |||
|  | 
 | |||
|  | Então, quando chamamos a função, isso é o que acontece: | |||
|  | ``` | |||
|  | (fact 5)  | |||
|  |  ; Loop 1: 5 != 1, so the loop recurs with 4 (5 - 1) and 5 (1 * 5).  | |||
|  |  ; Loop 2: 4 != 1, so the loop recurs with 3 (4 - 1) and 20 (5 * 4).  | |||
|  |  ; Loop 3: 3 != 1, so the loop recurs with 2 (3 - 1) and 60 (20 * 3).  | |||
|  |  ; Loop 4: 2 != 1, so the loop recurs with 1 (2 - 1) and 120 (60 * 2).  | |||
|  |  ; Loop 5: 1 == 1, so the function returns prod, which is now equal to 120.  | |||
|  |  ; => 120  | |||
|  | ``` | |||
|  | 
 | |||
|  | A coisa engenhosa sobre a recursão é que as variáveis em si nunca são alteradas. A única coisa que muda é o que `n` e `prod` _referem_ . Nós nunca dizemos, `n--` ou `n += 2` . | |||
|  | 
 | |||
|  | ## Por que usar loop / recorrer?
 | |||
|  | 
 | |||
|  | Você pode estar se perguntando por que você usaria `loop/recur` vez de simplesmente definir uma função que chama a si mesma. Nossa função fatorial poderia ter sido escrita assim: | |||
|  | ``` | |||
|  | (defn fact-no-loop [n]  | |||
|  |   (if (= 1 n)  | |||
|  |     1  | |||
|  |     (* n (fact-no-loop (dec n)))))  | |||
|  | ``` | |||
|  | 
 | |||
|  | Isso é mais conciso e funciona de maneira semelhante. Por que você _nunca_ usar loop e se repetem? | |||
|  | 
 | |||
|  | ### Otimização de Chamadas
 | |||
|  | 
 | |||
|  | Se você usar `loop/recur` , o compilador (o software que transforma o código Clojure em bytecode da JVM) sabe que você deseja criar um loop recursivo. Isso significa que ele tenta o máximo para otimizar seu código para recursão. Vamos comparar a velocidade do `fact` e o `fact-no-loop` : | |||
|  | ``` | |||
|  | (time (fact 20))  | |||
|  |  ; => "Elapsed time: 0.083927 msecs"  | |||
|  |  ;    2432902008176640000  | |||
|  |  (time (fact-no-loop 20))  | |||
|  |  ; => "Elapsed time: 0.064937 msecs"  | |||
|  |  ;    2432902008176640000  | |||
|  | ``` | |||
|  | 
 | |||
|  |  [IDEOne isso!](https://ideone.com/tpC0Xo) | |||
|  | 
 | |||
|  | Nesta escala, a diferença é insignificante. Na verdade, o `fact-no-loop` é ocasionalmente mais rápido que o `fact` devido à natureza imprevisível da memória do computador. No entanto, em uma escala maior, esse tipo de otimização pode tornar seu código muito mais rápido. | |||
|  | 
 | |||
|  | ### Recursão de aninhamento dentro de funções
 | |||
|  | 
 | |||
|  | `fact-no-loop` funciona sem `loop/recur` porque a função inteira é recursiva. E se quiséssemos que parte de nossa função usasse um loop recursivo e depois o resto fizesse algo não recursivo? Teríamos que definir duas funções totalmente separadas. Usando o `loop/recur` nos permite usar uma função pouco anônima. | |||
|  | 
 | |||
|  | | [ Anterior](//forum.freecodecamp.com/t/clojure-create-local-variables-with-let/18415) | [ Casa ](//forum.freecodecamp.com/t/clojure-resources/18422) | Próximo  |   | |||
|  | | [Vamos Bindings](//forum.freecodecamp.com/t/clojure-create-local-variables-with-let/18415) | [Índice](//forum.freecodecamp.com/t/clojure-resources/18422) | Ser adicionado | |