Clojure: Why does this give a StackOverflowError?

(reduce concat (repeat 10000 [])) 

I understand that flatten is probably the best way to do this, but I'm still wondering why this is causing the error.

+6
source share
2 answers

This is because concat creates a lazy sequence.

So when you call

 (concat ab) 

actual concatenation fails if you are not trying to use the result.

So, your code creates 10,000 nested lazy sequences, causing a StackOverflow error.

I see two ways to prevent a mistake.

The first way is to force concat using the doall function :

 (reduce (comp doall concat) (repeat 10000 [])) 

The second way is to use the greedy into function instead of the lazy concat :

 (reduce into (repeat 10000 [])) 

Update

As for your suggestion on using flatten , this is not a good solution because flatten is recursive, so it will try to smooth out all nested collections. Consider the following example:

 (flatten (repeat 3 [[1]])) 

It will produce a flattened sequence (1 1 1) instead of a concatenated one ([1] [1] [1]) .

I think the best solution would be to use concat with apply :

 (apply concat (repeat 10000 [])) 

Because it will generate a single lazy sequence without throwing a StackOverflow error.

+7
source

concat lazy, so all concat calls are saved until the results are used. doall enhances lazy sequences and can prevent this error:

 user> (reduce concat (repeat 10000 [])) StackOverflowError clojure.lang.RT.seq (RT.java:484) user> (reduce (comp doall concat) (repeat 10000 [])) () 
+2
source

All Articles