Clojure:为什么会产生StackOverflowError?

时间:2014-04-10 16:36:46

标签: clojure

(reduce concat (repeat 10000 []))

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

2 个答案:

答案 0 :(得分:7)

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

所以,当你打电话时

(concat a b)

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

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

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

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

(reduce (comp doall concat) (repeat 10000 []))

第二种方法是使用贪婪的into function而不是懒惰的concat

(reduce into (repeat 10000 []))

更新

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

(flatten (repeat 3 [[1]]))

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

我认为最好的解决方案是将concatapply

一起使用
(apply concat (repeat 10000 []))

因为它会产生单个延迟序列而不会抛出StackOverflow错误。

答案 1 :(得分:2)

concat是懒惰的,所以对concat的所有调用都会被保存,直到使用结果为止。 doall强制延迟序列并可以防止此错误:

user> (reduce concat (repeat 10000 []))
StackOverflowError   clojure.lang.RT.seq (RT.java:484)
user> (reduce (comp doall concat) (repeat 10000 []))
()