How to use tail recursion correctly?

大城市里の小女人 提交于 2020-01-06 18:57:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!