I’m trying to wrap my head around recursion with clojure. I’m getting a stack overflow error with the following code, can anyone spot the issue?
(I know this is inefficient but it’s strictly for learning purposes)
user=> (defn addall
([] 0)
([& x]
(if (empty? x) 0)
(+ (first x) (addall (rest x)))))
user/addall
user=> (addall 1)
StackOverflowError clojure.lang.ArraySeq.next (ArraySeq.java:78)
It looks like your parenthesization is wrong — your
ifneeds anelseform. I suspect you meant something like:But even with that fixed, your code is still wrong: it assumes that it’s called with multiple arguments —
(addall 1 2 3)— but recurs by passing itself a list —(addall [2 3]). This results in it getting stuck in a loop that doesn’t make any progress, which you can observe by adding aprintstatement:This actually produced a segfault on my computer!
Also, it has two base cases. I’d suggest this instead:
To be called with a vector:
Alternatively, if you want to use a variadic function, you’d also need
apply:That said, you should note that Clojure does not have tail-call optimization, which means that this code would fail with medium-sized inputs. Clojure encourages the use of
loop/recurand built-in sequence processing functions instead.