Why aren't recursive calls automatically replaced with recur?

In the next (Clojure) SO question: my own insert function as an exercise

The accepted answers say the following:

Replace the recursive call with a call to repeat because, as written, the stack overflow will hit

(defn foo [stuff]
  (dostuff ... )
  (foo (rest stuff)))

becomes:

(defn foo [stuff]
  (dostuff ...)
  (recur (rest stuff)))

to avoid stack flushing.

This might be a dumb question, but I wonder why the recursive call to foo will not be automatically replaced by recur?

In addition, I made another example of SO and wrote this (without using cond specifically to just try):

(defn is-member [elem ilist]
  (if (empty? ilist)
    false
    (if (= elem (first ilist))
      true
      (is-member elem (rest ilist)))))

And I was wondering if I should replace the is-member call with recur (which also seems to work) or not.

Are there cases where you recurs and in particular should not use recur?

+5
3

, recur, , , , , .

, , recur , ; recur, , recur ( , recur --.) , .

recur Clojure , TCO , Scheme; Clojure , Java, JVM . recur , , .

, - , recur , , , , - .

+8

, ( )

" "

, , , - , . , ,

+7

, is-member recur

, mquander, recur , . ( ) , ( ).

(.. "recur" ) , .

, recur?

, ,

  • - .. - .
  • .

:

 (defn foo [coll] 
  (when coll 
    (println (first coll))
    (recur (next coll)))   ;; OK: Tail recursive

(defn fie [coll]
  (when coll
    (cons (first coll)       
      (fie (next coll))))) ;; Can't use recur: Not tail recursive.   

(defn fum 
  ([coll] 
    (fum coll []))         ;; Can't use recur: Different function.
  ([coll acc] 
    (if (empty? coll) acc
       (recur (next coll)  ;; OK: Tail recursive
          (conj acc (first coll)))))) 

, recur , : , , - ( recur).

"" " StackOverflowError", , , - , , - , .

+3
source

All Articles