## Pratical Cljr – loop/recur

Programming Clojure这块写的过于简单, Pratical Clojure写的还不错, 这本书在某些章节写的深度不错, 讨论why, 而不是仅仅how, 故摘录

It will probably come as a minor shock to users of imperative programming languages that Clojure provides no direct looping syntax.
Instead, like other functional languages, it uses recursion in scenarios where it is necessary to execute the same code multiple times.

Thinking recursively is one of the largest challenges coming from imperative to functional languages, but it is surprisingly powerful and elegant, and you will soon learn how to easily express any repeated computation using recursion.

For effective recursion in Clojure (or any other functional language, for that matter), you only need to keep these guidelines in mind:

• Use a recursive function’s arguments to store and modify the progress of a computation. In imperative programming languages, loops usually work by repeatedly modifying a single variable.

• Make sure the recursion has a base case or base condition.

• With every iteration, the recursion must make at least some progress towards the base condition.

Uses Newton’s algorithm to recursively calculate the square root of any number.

(defn abs
"Calculates the absolute value of a number"
[n]
(if (< n 0)
(* -1 n)
n))

(defn avg
"returns the average of two arguments"
[a b]
(/ (+ a b) 2))

(defn good-enough?
"Tests if a guess is close enough to the real square root"
[number guess]
(let [diff (- (* guess guess) number)]
(if (< (abs diff) 0.001)
true
false)))

(defn sqrt
"returns the square root of the supplied number"
([number] (sqrt number 1.0)) ;Clojure实现默认参数真是比较麻烦
([number guess]
(if (good-enough? number guess)
guess
(sqrt number (avg guess (/ number guess))))))

uses recursion to calculate exponents, 幂操作

(defn power
"Calculates a number to the power of a provided exponent."
[number exponent]
(if (zero? exponent)
1
(* number (power number (- exponent 1)))))

One practical problem with recursion is that, due to the hardware limitations of physical computers, there is a limit on the number of nested functions (the size of the stack).
There is a strict limit on the number of times a function can recur. For small functions, this rarely matters. But if recursion is a generic and complete replacement for loops, it becomes an issue. There are many situations in which it is necessary to iterate or recur indefinitely.
Historically, functional languages resolve this issue through tail-call optimization. Tail-call optimization means that, if certain conditions are met, the compiler can optimize the recursive calls in such a way that they do not consume stack. Under the covers, they’re implemented as iterations in the compiled machine code.

The only requirement for a recursive call to be optimized in most functional languages is that the call occurs in tail position. There are several formal definitions of tail position, but the easiest to remember, and the most important, is that it is the last thing a function does before returning.

#### Clojure’s recur

In some functional languages, such as Scheme, tail call optimization happens automatically whenever a recursive call is in tail position.
Clojure does not do this. In order to have tail recursion in Clojure, it is necessary to indicate it explicitly using the recur form.

To use recur, just call it instead of the function name whenever you want to make a recursive call. It will automatically call the containing function with tail-call optimization enabled.

Clojure has come under fire from some quarters for not doing tail-call optimization by default, whenever possible, without the need for the recur special form.
Although the invention of recur was spurred by the limitations of the JVM that make it difficult to do automatic tail optimization, many members of the Clojure community find that having explicit tail recursion is much clearer and more convenient than having it implicitly assumed. With Clojure, you can tell at a glance if a function is tail recursive or not, and it’s impossible to make a mistake.
If something uses recur, it’s guaranteed never to run out of stack space due to recursion. And if you try to use recur somewhere other than in correct tail position, the compiler will complain. You are never left wondering whether a call is actually in tail position or not.

(defn add-up
"adds all the numbers below a given limit"
([limit] (add-up limit 0 0 ))
([limit current sum]
(if (< limit current)
sum
(add-up limit (+ 1 current) (+ current sum)))))

user=> (add-up 3)
6
125250

java.lang.StackOverflowError

Clojure本身不会做任何优化, 你必须自己使用recur替换函数名, 问题解决了, 因为此时不会真正的递归, 而只是iteration

(defn add-up
"adds all the numbers up to a limit"
([limit] (add-up limit 0 0 ))
([limit current sum]
(if (< limit current)
sum
(recur limit (+ 1 current) (+ current sum)))))

12502500

#### Using loop

To define a loop construct, use the loop form. It in turn takes two forms: first, a vector of initial argument bindings (in name/value pairs) and an expression for the body.

(defn add-up
"adds all the numbers up to a limit"
[limit]
(loop [current 0 sum 0]
(if (< limit current)
sum
(recur (+ 1 current) (+ current sum)))))

12502500