Clojure: Can only recur from tail position

clojure, recursion

Solution

The error `Can only recur from tail position` means that you're not calling `recur` as the last expression in the recursive part of the function - in fact, in your code `conj` is the last expression.

Some improvements to make your code work:

- Ask if the collection is empty as the base case, instead of comparing if its length is less than two

- `conj` receives a collection for its first parameter, not an element

- It's a better idea to use `cons` instead of `conj` (which adds new elements at different places depending on the concrete type of the collection, according to the documentation). In this way the returned collection will be reversed if the input collection is either a list or a vector (although the type of the returned collection will always be `clojure.lang.Cons`, no matter the type of the input collection)

- Be aware that `'(coll)` is a list with a single element (the symbol `coll`) and not the actual collection

- For correctly reversing a list you need iterate over the input list and append each element to the beginning of an output list; use an accumulator parameter for this

- For taking advantage of tail-recursion call `recur` at the tail position of the function; in this way each recursive invocation takes a constant amount of space and the stack won't grow unbounded

I believe this is what you were aiming for:

(defn recursive-reverse [coll]
  (loop [coll coll
         acc  (empty coll)]
        (if (empty? coll)
            acc
            (recur (rest coll) (cons (first coll) acc)))))

Problem

I'm trying to recursively reverse a list, but am getting `Can only recur from tail position` upon run. What does this mean precisely and how can my code be improved so it works? ``` (defn recursive-reverse [coll] (loop [coll coll] (if (< (count coll) 2) '(coll) (conj (first coll) (recur (rest coll))) ))) ``` EDIT Output for Oscar's solution. It works for lists but not vectors? ``` user=> (= (recursive-reverse [1 2 3 4 5]) (recursive-reverse '(1 2 3 4 5))) false user=> (= '(1 2 3 4 5) [1 2 3 4 5]) true user=> (recursive-reverse [1 2 3 4 5]) [1 2 3 4 5] user=> (recursive-reverse '(1 2 3 4 5)) (5 4 3 2 1) ```

Original source

Related problems