Joe*_*Joe 23 stack-overflow recursion reduce clojure
我正在尝试连接一系列Seqs.
我可以做到apply concat
.
user=> (count (apply concat (repeat 3000 (repeat 3000 true))))
9000000
Run Code Online (Sandbox Code Playgroud)
但是,根据我有限的知识,我会假设使用apply
力量来实现懒惰的Seq,这对于非常大的输入来说似乎并不合适.如果可以的话,我宁愿懒洋洋地这样做.
所以我认为使用reduce
就可以完成这项工作.
user=> (count (reduce concat (repeat 3000 (repeat 3000 true))))
Run Code Online (Sandbox Code Playgroud)
但这导致了
StackOverflowError clojure.lang.RT.seq (RT.java:484)
Run Code Online (Sandbox Code Playgroud)
我很惊讶,因为我会认为语义reduce
意味着它是尾调用的递归.
两个问题:
apply
是最好的方法吗?reduce
一般不适合大投入?A. *_*ebb 28
apply
.当函数参数是惰性时,也是如此apply
.让我们检查一下对底层子序列的计数副作用:
(def counter (atom 0))
(def ss (repeatedly 3000
(fn [] (repeatedly 3000
(fn [] (do (swap! counter inc) true))))))
(def foo (apply concat ss))
so.core=> @counter
0
so.core=> (dorun (take 1 foo))
nil
so.core=> @counter
1
so.core=> (dorun (take 3001 foo))
nil
so.core=> @counter
3001
Run Code Online (Sandbox Code Playgroud)
reduce
concat
由于thunk组成而导致大量s溢出延迟序列,例如由concat
thunk 产生的序列,延迟函数调用.当你concat
的结果是concat
你已经在另一个thunk中嵌套thunk.在你的函数中,嵌套深度为3000,因此一旦请求第一个项目并且展开3000个嵌套的thunk,堆栈就会溢出.
so.core=> (def bar (reduce concat (repeat 3000 (repeat 3000 true))))
#'so.core/bar
so.core=> (first bar)
StackOverflowError clojure.lang.LazySeq.seq (LazySeq.java:49)
Run Code Online (Sandbox Code Playgroud)
懒惰序列的实现通常会在seq
编辑时展开嵌套的thunks trampoline样式并且不会打击堆栈:
so.core=> (loop [lz [1], n 0]
(if (< n 3000) (recur (lazy-seq lz) (inc n)) lz))
(1)
Run Code Online (Sandbox Code Playgroud)
但是,如果你seq
在实现它的同时在未实现部分的惰性序列中调用...
so.core=> (loop [lz [1], n 0]
(if (< n 3000) (recur (lazy-seq (seq lz)) (inc n)) lz))
StackOverflowError so.core/eval1405/fn--1406 (form-init584039696026177116.clj:1)
so.core=> (pst 3000)
Run Code Online (Sandbox Code Playgroud)
StackOverflowError so.core/eval1619/fn--1620 (form-init584039696026177116.clj:2) clojure.lang.LazySeq.sval (LazySeq.java:40) clojure.lang.LazySeq.seq (LazySeq.java:49) clojure.lang.RT.seq (RT.java:484) clojure.core/seq (core.clj:133) so.core/eval1619/fn--1620 (form-init584039696026177116.clj:2) clojure.lang.LazySeq.sval (LazySeq.java:40) clojure.lang.LazySeq.seq (LazySeq.java:49) clojure.lang.RT.seq (RT.java:484) clojure.core/seq (core.clj:133) ... (repeatedly)
然后你最终建立seq
堆栈帧.实施concat
就是这样.检查StackOverflowError的堆栈跟踪,您concat
会看到类似的.
归档时间: |
|
查看次数: |
1543 次 |
最近记录: |