从向量/切片-seq构建的lazy-seqs有时候首次/后续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加倍,不是慢两倍,而是慢十倍
(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. Should ChunkedCons implement IReduce? I think so.