6
votes
(reduce concat (repeat 10000 []))

I understand that flatten is probably a better way to do this but I am still curious as to why this causes an error.

2
I added a bit about flatten to my answer.Leonid Beschastny
Thanks Leonid, apply concat is a nice solution.user2179977

2 Answers

7
votes

It's because concat produces a lazy sequence.

So, when you're calling

(concat a b)

no actual concatenation is done unless you're trying to use the result.

So, your code creates 10000 nested lazy sequences, causing StackOverflow error.

I can see two ways to prevent it from throwing an error.

First way is to force concat execution using doall function:

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

Second way is to use greedy into function instead of lazy concat:

(reduce into (repeat 10000 []))

Update

As for your suggestion about using flatten, it's not a good solution, because flatten is recursive, so it'll try to flatten all nested collections as well. Consider the following example:

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

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

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

(apply concat (repeat 10000 []))

Because it will produce single lazy sequence without throwing StackOverflow error.

2
votes

concat is lazy, so all the calls to concat are saved up until the results are used. doall forces 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 []))
()