简体   繁体   中英

How to use tail recursion correctly?

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM