Clojure:为什么会产生StackOverflowError?

use*_*977 6 clojure

(reduce concat (repeat 10000 []))
Run Code Online (Sandbox Code Playgroud)

我知道这flatten可能是一个更好的方法,但我仍然很好奇为什么这会导致错误.

Leo*_*tny 7

这是因为concat产生了一个懒惰的序列.

所以,当你打电话的时候

(concat a b)
Run Code Online (Sandbox Code Playgroud)

除非您尝试使用结果,否则不会进行实际连接.

因此,您的代码会创建10000个嵌套的延迟序列,从而导致StackOverflow错误.

我可以看到两种方法来防止它抛出错误.

第一种方法是concat使用doall函数强制执行:

(reduce (comp doall concat) (repeat 10000 []))
Run Code Online (Sandbox Code Playgroud)

第二种方法是使用贪婪into功能而不是懒惰concat:

(reduce into (repeat 10000 []))
Run Code Online (Sandbox Code Playgroud)

更新

至于你关于使用的建议flatten,它不是一个好的解决方案,因为它flatten是递归的,所以它也会试图压扁所有嵌套的集合.请考虑以下示例:

(flatten (repeat 3 [[1]]))
Run Code Online (Sandbox Code Playgroud)

它将产生扁平的序列(1 1 1)而不是连接的序列([1] [1] [1]).

我认为,最好的解决办法是使用concat具有apply:

(apply concat (repeat 10000 []))
Run Code Online (Sandbox Code Playgroud)

因为它会产生单个懒惰序列而不会抛出StackOverflow错误.