Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using partial over a collection, reduce -vs- apply

Tags:

clojure

I have this curious demonstration of partials. Here is the code:

Start by declaring a vector and a partial. As expected, reduce and apply sums the integers on vector a:

> (def a [1 2 3 4 5])
> (def p (partial + 10))
> (apply + a)
15
> (reduce + a)
15

Now, using apply on the partial p and vector a, I'm getting the sum of a and the +10 from the partial, which makes sense:

> (apply p a)
25

Now, using (reduce) makes no sense to me. Where is 55 coming from?

> (reduce p a)
55

The closest I can come up with is, (reduce) version is adding 10 from the 1 index and ignoring the zero index before adding everything together:

> (+ (first a) (reduce + (map #(+ % 10) (rest a))))
55

I'm just curious if anyone knows what is happening here, exactly? I don't really know what answer I'm expecting with this, but I also don't understand what is happening either. I have no idea why I would get 55 as an answer.

like image 856
dizzystar Avatar asked Mar 22 '21 04:03

dizzystar


2 Answers

The first thing to note is that + is variadic: it can be called with zero, one, two, or more arguments. When you do (apply + a) you are essentially calling + with five arguments and getting the sum back (15).

However, reduce treats the function as strictly binary and calls it repeatedly, with the result of the previous call as the first argument of the next call. (reduce + a) is (+ (+ (+ (+ 1 2) 3) 4) 5) which also happens to be 15.

So your partial is also variadic and can be called with five arguments, as in the apply call: (apply p a) = (p 1 2 3 4 5) = (+ 10 1 2 3 4 5) so you get 25.

The reduce on p is going to call it repeatedly as shown above, but this time the function adds 10 in each time: (reduce p a) = (p (p (p (p 1 2) 3) 4) 5) = (+ 10 (+ 10 (+ 10 (+ 10 1 2) 3) 4) 5) so you get four 10s and the 15 making 55.

like image 101
Sean Corfield Avatar answered Nov 06 '22 03:11

Sean Corfield


Another way of looking at Sean Corfield's fine answer:

Given

(def p (partial + 10))

then (p x y) means (+ 10 x y), for any x and y.

So

(reduce p a)

means

(reduce (fn [x  y] (+ 10  x  y)) a)

... since the first argument to reduce is a function of two arguments.

No initial value is supplied, so (first a) is used as such, and the reduction is applied to (rest a), which has four elements.

  • All the elements of a get added in: the first as the initial value; the others by reduction.
  • The 10 gets added on in every cycle of the reduction: four times.

So the final result is the same as

(+ (* 10 (dec (count  a))) (reduce + a))

In this case, 55.

like image 2
Thumbnail Avatar answered Nov 06 '22 05:11

Thumbnail