由向量/分块序列构建的懒惰序列有时可能会进行低速的首次/下一次 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}} 后,它将不会逃脱到快速路径,而是保持在首次/下一次。
注意:在 Clojure 中,它们“适当”地进行缩放(前 3 个约为 45ms,最后 2 个约为 110ms)。
原因是 Clojure 正确地逃离到快速路径
https://github.com/clojure/clojure/blob/2b242f943b9a74e753b7ee1b951a8699966ea560/src/clj/clojure/core/protocols.clj#L131-L143
这是一个 RFC,因为我不完全确定实施细节。需要小心不要炸毁堆栈...
问题
1. 分块 Cons 应该实现 IReduce 吗?我认为是的。