As the main answer suggests, the list concat is the offender. Calling "doall", with that list as input... will result in an ISeq :
;;insertion sort helper
(defn insert [s k]
;;find the insert point
(let [spl (split-with #(< % k) s)
ret (concat (first spl) (list k) (last spl))]
(doall ret)))
;;insertion sort
(defn insert-sort [s]
(reduce (fn [s k] (insert s k)) '() s))
But wait... Is the sequence still lazy ?
The following hack of the above code, interestingly, indicates that the sequence is indeed still lazy !
;;insertion sort helper
(defn insert [s k]
;;find the insert point
(let [spl (split-with #(< % k) s)
ret (concat (first spl) (list k) (last spl))
ret2 (doall ret)
_ (println "final " (.getClass ret2))]
ret2))
;;insertion sort
(defn insert-sort [s]
(reduce (fn [s k] (insert s k)) '() s))
So, if the list is still lazy, then why does the use of doall fix anything ?
The "doall" function is not gauranteed to return a "non lazy" list, but rather, it gaurantees that the list which it DOES return will have been evaluated by a full walk through through.
Thus, the essence of the problem is the multiple function calls, the laziness is certainly related to this aspect of the code in your original question, but it is not the "primary" source of the overflow.