Ankur 的回答是正确的。另外,我认为这个链接很好地解释了事情:
http://www.learningclojure.com/2010/08/reduce-not-scary.html
现在,回答你的问题...
是的。第二个参数reduce
是累加器的初始值。
是的,它始终是一个累加器。的全部意义在于reduce
它可以让你以一种功能性和不可变的方式进行积累。
我会注意到,可以以reduce
累积无关紧要的方式使用,就像在 mikera 的回答中一样。在那种情况下,reduce
仍然在做累加(内部),但它一遍又一遍地使用相同的值,所以它没有明显的效果。
当reduce
只使用两个参数调用时...... Clojure 使用的规则有点复杂,但归结为......
(reduce + [1 2 3])
...将使用序列的第一个元素作为初始值,这意味着它与此相同:
(reduce + 1 [2 3])
你问什么是蓄能器。累加器是在循环某些东西时累积数据的概念。
在命令式语言中,累加器通常是一个在循环时发生变异的变量。让我们看一下 Leonel 的示例,稍作修改:
var sum = 0;
for (var i = 0; i < 10; ++i) {
sum = sum + i;
}
return sum;
起初,这似乎不可能以功能性的方式完成。但是reduce
,你可以!
(reduce (fn [sum i] (+ sum i)) 0 (range 0 10))
这是如何工作的,reduce
需要三个参数:
- 转换函数
- 累加器的初始值
- 一个序列
它使用两个参数调用转换函数:
sum
是累加器的当前值
i
是序列的当前元素
现在,无论转换函数返回什么,都将用作累加器的当前值。换句话说......第一次迭代sum
将是初始值。在第一次迭代之后,是前sum
一次迭代中返回的转换函数。
reduce
如果我在 JavaScript 中编写一个使用突变的实现,也许会有所帮助:
function reduce(f, init, coll) {
for (var i = 0; i < coll.length; ++i) {
init = f(init, coll[i]);
}
return init;
}
reduce(function (sum, i) { return sum + i }, 0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
如您所见,该reduce
函数看起来与之前的命令式代码非常相似。
现在让我们reduce
在 Clojure 中以一种没有变异的函数方式实现:
(defn reduce [f init coll]
(if-let [s (seq coll)]
(reduce f (f init (first s)) (rest s))
init))
(reduce (fn [sum i] (+ sum i)) 0 (range 0 10))
但是不管是reduce
可变的还是不可变的积累,都是在做积累。
有趣的是,值得注意的是 Clojurereverse
使用以下方法实现reduce
:
(defn reverse
"Returns a seq of the items in coll in reverse order. Not lazy."
{:added "1.0"
:static true}
[coll]
(reduce1 conj () coll))
弄清楚为什么会这样是一个有趣的心理练习。
你也可以做一些简洁的事情,比如使用 reduce 实现 map、filter 和其他东西。但我认为这超出了你的问题。