Clojure:为什么会出现StackOverflower错误?
我知道展平可能是一种更好的方法,但我仍然很好奇为什么这会导致错误。这是因为产生了一个惰性序列 那么,当你打电话的时候Clojure:为什么会出现StackOverflower错误?,clojure,Clojure,我知道展平可能是一种更好的方法,但我仍然很好奇为什么这会导致错误。这是因为产生了一个惰性序列 那么,当你打电话的时候 (reduce concat (repeat 10000 [])) 除非您试图使用结果,否则不会进行实际的连接 因此,您的代码创建10000个嵌套的惰性序列,从而导致StackOverflow错误 我可以看到两种防止它抛出错误的方法 第一种方法是使用以下方法强制执行concat: 第二种方法是使用贪婪而不是懒惰concat: (reduce (comp doall concat
(reduce concat (repeat 10000 []))
除非您试图使用结果,否则不会进行实际的连接
因此,您的代码创建10000个嵌套的惰性序列,从而导致StackOverflow错误
我可以看到两种防止它抛出错误的方法
第一种方法是使用以下方法强制执行concat
:
第二种方法是使用贪婪而不是懒惰concat
:
(reduce (comp doall concat) (repeat 10000 []))
更新
至于您关于使用展平
的建议,这不是一个好的解决方案,因为展平
是递归的,所以它也会尝试展平所有嵌套集合。考虑下面的例子:
(reduce into (repeat 10000 []))
它将生成展平序列(11)
,而不是级联序列([1][1][1])
我认为最好的解决方案是使用concat
和apply
:
(flatten (repeat 3 [[1]]))
因为它将生成单个延迟序列,而不会抛出StackOverflow错误。
concat
是延迟的,所以所有对concat的调用都会被保存,直到结果被使用为止doall
强制执行惰性序列并可防止此错误:
(apply concat (repeat 10000 []))
我在回答中添加了一点关于“展平”的内容。谢谢Leonid,
apply concat
是一个很好的解决方案。同意展平。展平几乎从来都不是正确的做法。@leonid beschastny为什么“10000个嵌套的惰性序列”会导致堆栈溢出错误?@Thumbnail,因为惰性序列只是生成另一个序列的函数。因此,执行这种惰性序列将产生10000个嵌套函数调用,这正是堆栈溢出的情况。@Thumbnail当您调用(lazy seq x)
clojure创建一个函数,该函数在调用时将产生x
(如果x
不是序列,则抛出一个错误)。它不知道什么是x
。因此,如果x
是另一个惰性序列,则需要另一个函数调用来查找其中的内容。在我们的例子中,需要10000个嵌套调用才能发现序列实际上是空的。。。
(apply concat (repeat 10000 []))
user> (reduce concat (repeat 10000 []))
StackOverflowError clojure.lang.RT.seq (RT.java:484)
user> (reduce (comp doall concat) (repeat 10000 []))
()