When you call reduce and pass it a function and two arguments, can the first argument be considered to be an accumulator?
Is it always an accumulator?
Is it sometimes an accumulator?
I was reading a blog entry about using Clojure to parse big files and found this line:
(reduce line-func line-acc (line-seq rdr))
Link to the blog entry:
http://lethain.com/reading-file-in-clojure/
What about a simple: (reduce + [1 2 3])? Is there an accumulator involved?
I take it my question boils do to: "What is exactly an accumulator?"
But I'd still like to understand too the relation between an accumulator and the reduce function. So any answer to these specific (related) questions are most welcome!
No. It's an argument to function f. This means f
is applied over val and the first element in coll.
For instance:
(reduce + 1 [2 3 4]) ;; 10
(reduce + (cons 1 [2 3 4])) ;; 10
No. It's as a series of applications of function f
; like this:
(reduce f [1 2 3 4]) ; ==> (f (f (f 1 2) 3) 4)
(reduce f 1 [2 3 4]) ; ==> (f (f (f 1 2) 3) 4)
Notice that in both cases, the inner-most call to f
takes parameters 1 and 2 ? In the first case, 1 and 2 are the first and second elements of coll; in the second case, 1 is the lone value and 2 is the first element of coll.
An accumulator is a variable that holds intermediate results of a computation. Like in this snippet of Java:
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
return sum;
Here, the value of variable sum is changed as the loop progresses. In Clojure, variables are immutable, so you do not see this idiom. Instead, the accumulator is more often (but not always) a parameter to a recursive function.
For instance, here's a function which reverses a list by "accumulating" the first entry in the list into the front of an accumulator. In this case, the variable is not changed, but is passed to another call to the function.
(defn reverse [[f & r] acc]
(if (nil? f)
acc
(recur r (conj acc f))))
(reverse [1 2 3] ()) ;; [3 2 1]
It can be an accumulator.
It depends on how you use it, and also on your definition of "accumulator".
Here's a traditional, mutable accumulator, note the need to continue to pass the same accumulator on at each step:
(reduce
(fn [atom val] (do (swap! atom + val) atom))
(atom 10)
[1 2 3 4 5])
=> #<Atom@115872f5: 25>
Here's reduce being used with an immutable "accumulator". Although accumulators are traditionally mutable, I think most functional programmers would define this as an accumulator:
(reduce + 10 [1 2 3 4 5])
=> 25
Here's a reduce where you don't accumulate anything, so it's hard to make a case that the second argument is an accumulator:
(reduce
(fn [_ x] (println x))
nil
[1 2 3])
I am assuming the original question is using accumulator as a generic term, not an official term used in a language.
I do not know if the first argument after the function (the second argument) would be called an accumulator in Clojure's terms. But it certainly seems to act that way.
In the following:
(defn reduce-csv-row
"Accepts a csv-row (a vector) a list of columns to extract,
and reduces the csv-row to a smaller list based on selection
using the values in col-nums (a vector of integer vector
positions.)"
[csv-row col-nums]
(reduce
(fn [filter-csv-row col-num]
;Don't use vectors without the proper information in them.
(if-not (<= (count csv-row) 1)
(conj filter-csv-row (nth csv-row col-num nil))))
[]
col-nums))
I certainly expect a sequence returned after calling this function, so accumulator might not be a bad term, but as an official term, I cannot say.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With