文档中的语言混淆了减速器和转换器。转换器可以被认为是简化器的优化实现,其目标是减少对象分配(和后续 GC)。这种优化不会改变 reducer 的概念模型。
所以,坚持简单的reduce,它的目标是简单地提供一种从序列中累积结果的方法。最简单的例子是对一个序列求和:
(ns clj.core
(:require [clojure.string :as str] )
(:use tupelo.core)) ; it->
(def values (range 6))
(spyx values)
(def total (reduce + 0 values))
(spyx total)
;=> values => (0 1 2 3 4 5)
;=> total => 15
但是,“减少功能”可以做任何事情。它还可以返回一个序列,而不仅仅是一个标量值:
(def duplicate (reduce (fn [cum-result new-val] ; accumulating function
(conj cum-result new-val))
[] ; initial value
values)) ; sequence to process
(spyx duplicate)
;=> duplicate => [0 1 2 3 4 5]
这是一个计算输入序列积分的更复杂的归约函数:
(def integral (reduce (fn [cum-state new-val] ; accumulating function
(let [integ-val (+ (:running-total cum-state) new-val) ]
{ :integ-vals (conj (:integ-vals cum-state) integ-val)
:running-total integ-val} ))
{:integ-vals [] :running-total 0} ; initial value
values)) ; sequence to process
(spyx integral)
;=> integral => {:integ-vals [0 1 3 6 10 15], :running-total 15}
所以这是与map 相比的最大区别。我们称map为:
(def y (map f x))
其中x 和y 是序列,结果看起来像
y(0) = f( x(0) ) ; math notation used here
y(1) = f( x(1) )
y(2) = f( x(2) )
...
所以每个 y(i)仅依赖于函数 f 和 x(i)。相比之下,我们将reduce 定义为:
(def y (reduce f init x))
其中x 和y 是序列,init 是标量(如0 或[])。结果看起来像
y(0) = f( init, x(0) ) ; math notation used here
y(1) = f( y(0), x(1) )
y(2) = f( y(1), x(2) )
...
所以归约函数f是2个值的函数:累加结果和新的x值。