由向量/分块序列构建的懒序列有时会进行较慢的第一个/下一个 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 吗?我觉得应该是的。