问题
I am trying to rewrite this piece of code from https://github.com/lspector/gp/blob/master/src/gp/evolvefn_zip.clj
to use recur:
(defn random-code [depth]
(if (or (zero? depth)
(zero? (rand-int 2)))
(random-terminal)
(let [f (random-function)]
(cons f (repeatedly (get function-table f)
#(random-code (dec depth)))))))
The problem is, I have absolutely no idea how to do that.
The only thing I can think of is something like this:
(defn random-code [depth]
(loop [d depth t 0 c []]
(if (or (zero? depth)
(zero? (rand-int 2)))
(if (= t 0)
(conj c random-terminal)
(recur depth (dec t) (conj c (random-terminal))))
(let [f (random-function)]
(if (= t 0)
(recur (dec depth) (function-table f) (conj c f))
(recur depth (dec t) (conj c f)))))))
It's not a working piece of code, it's just to show the way I would try to solve it, it would only get more and more convoluted.
Is there a better way to convert normal recursion to tail recursion in clojure?
回答1:
Here are 2 examples comparing a recursive algorithm and loop-recur
:
(defn fact-recursion [n]
(if (zero? n)
1
(* n (fact-recursion (dec n)))))
(defn fact-recur [n]
(loop [count n
result 1]
(if (pos? count)
(recur (dec count) (* result count))
result )))
(fact-recursion 5) => 120
(fact-recur 5) => 120
(defn rangy-recursive [n]
(if (pos? n)
(cons n (rangy-recursive (dec n)))
[n]))
(defn rangy-recur [n]
(loop [result []
count n]
(if (pos? count)
(recur (conj result count) (dec count))
result)))
(rangy-recursive 5) => (5 4 3 2 1 0)
(rangy-recur 5) => [5 4 3 2 1]
The basic difference is that for loop-recur
you need a 2nd loop "variable" (here named result
) to accumulate the output of the algorithm. For plain recursion, the call stack accumulates the intermediate result.
来源:https://stackoverflow.com/questions/42379741/how-to-use-tail-recursion-correctly