由向量/分块seq构建的惰性seq有时会进行缓慢的初始/后续reduce操作。
观察
`
(def xs (vec (range 3000000)))
(time (reduce max xs)) ;; #1: 130ms, (参考)
(time (reduce max (lazy-cat xs))) ;; #2: 130ms,同样快
(time (reduce max 0 (lazy-cat xs))) ;; #3: 500ms,4倍慢!!
;; 使用concat将其加倍,它们不是2倍慢,而是10倍慢
(time (reduce max (lazy-cat xs xs))) ;; #4: 1200ms
(time (reduce max 0 (lazy-cat xs xs))) ;; #5: 1200ms
`
对#3的解释:问题在于{{seq-reduce}}在未调用{{init}}时将调用{{reduce}}并采取快速路径。当给了{{init}}时,它将永远不会逃逸到一个更快的reduce,而会坚持最初/后续。
注意:在Clojure中,它们的比例“正确”(前三个大约是45ms,最后两个大约是110ms)。
原因是Clojure正确地逃逸到了一个快速路径
https://github.com/clojure/clojure/blob/2b242f943b9a74e753b7ee1b951a8699966ea560/src/clj/clojure/core/protocols.clj#L131-L143
这是一个RFC,因为我不十分确定实施。需要小心不要遍地栈...
问题
1. ChunkedCons应该实现IReduce吗?我认为如此。