Как следует из основного ответа, список concat является нарушителем.Вызов "doall" с этим списком в качестве входных данных ... приведет к 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))
Но подождите ... Последовательность все еще ленива?
Интересно, что следующий взлом вышеупомянутого кода показывает, что последовательность действительно все еще ленива!
;;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))
Итак, если список все еще ленив, то почему использование doall что-то исправляет?
Функция «doall» не гарантируется для возврата«не ленивый» список, но, скорее, он гарантирует, что список, который он возвращает, будет оценен путем полного анализа.
Таким образом, суть проблемы заключается в множественных вызовах функций, лень, безусловно, связана с этим аспектом кода в исходном вопросе, но это не «основной» источник переполнения.