由 vector/chunked-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 乘以两倍,它们不是慢两倍,而是慢 10 倍
(time (reduce max (lazy-cat xs xs))) ;; #4: 1200ms
(time (reduce max 0 (lazy-cat xs xs))) ;; #5: 1200ms
`
对于 #3 的解释:问题在于没有提供 {{init}} 时,{{seq-reduce}} 不会适时地再次调用 {{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?我认为是的。