concat is a tricky little function. The name suggests a way to combine two collections. And it is, if you have only two collections. But it’s not as general as you might think. It’s not really a collection function at all. It’s a lazy sequence function. The difference can be important.

Here’s an example that I see a lot in the wild. Say you have a loop that builds up some result collection as the concatenation of several intermediate results:

( defn next-results "Placeholder for function which computes some intermediate collection of results." [n] (range 1 n)) ( defn build-result [n] ( loop [counter 1 results []] ( if (< counter n) ( recur (inc counter) (concat results (next-results counter))) results)))

The devilish thing about this function is that it works just fine when n is small.

(take 21 (build-result 100))

But when n gets sufficiently large, suddenly this happens:

(first (build-result 4000))

In the stack trace, we see concat and seq repeated over and over:

( .printStackTrace *e *out* )