Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Why does this give a StackOverflowError?

Tags:

clojure

(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.

like image 358
user2179977 Avatar asked Apr 10 '14 16:04

user2179977


2 Answers

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.

like image 59
Leonid Beschastny Avatar answered Oct 15 '22 23:10

Leonid Beschastny


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 []))
()
like image 2
noisesmith Avatar answered Oct 16 '22 00:10

noisesmith