Ada Chan
Ada Chan

Reputation: 31

Partial in Clojure takes more than one function

I am trying to really understand partial in Clojure. partial takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args. This is the working example for partial seems not making sense to me ((partial map *) [1 2 3] [4 5 6] [7 8 9]). map and * are functions; therefore partial is taking more than one function and invalidating the definition. Anyone can help me understand better?

Upvotes: 2

Views: 258

Answers (4)

Chris Murphy
Chris Murphy

Reputation: 6509

There is nothing wrong with a function being an argument. In your case map * is created, which can be used later:

(def will-map-multiply (partial map *))

As with any partial function the rest of its arguments can be supplied later:

(will-map-multiply [1 2 3] [4 5 6] [7 8 9]) ;=> (28 80 162)

That was 'partialising' one of the arguments. It could have been two:

(def will-map-multiply-again (partial map * [1 2 3]))
(will-map-multiply-again [4 5 6] [7 8 9]) ;=> (28 80 162)

When using partial the first parameter must be a function, and the others can be whatever - no reason they can't also be functions.

Your example is a bit complex because multiplying requires two or more arguments, and hence map needs two or more sequences.

Upvotes: 2

user771505
user771505

Reputation:

Functions are first-class values in Clojure. This means, you can pass them around like, for example, integers, maps or strings.

So, there’s nothing strange with (partial map *), where function * is just a map’s first argument. In your case, partial constructs a function which then passes additional collections to map. Let's see:

(partial map *)

;; becomes

(fn [coll1 coll2 coll3] ;; other arities ommited
  (map * coll1 coll2 coll3))

;; let’s call this fn with your collections

((fn [coll1 coll2 coll3]
 (map * coll1 coll2 coll3)) [1 2 3] [4 5 6] [7 8 9])

;; becomes

(map * coll1 coll2 coll3)

Again, the main point is that functions are first-class in Clojure and many other functional languages.

Hope this helps!

Upvotes: 1

Terminus
Terminus

Reputation: 949

(partial map *) looks strange, but when one realizes that map takes a function as its first argument, it becomes more clear. * is just a function that takes variable number of arguments and multiplies them. Therefore, (map * [1 2 3] [4 5 6] [7 8 9]) applies * to three triples of numbers and produces [28 80 162]. All this has nothing to do with partial. The confusion stems from the fact that in clojure functions are often passed as arguments to other functions (actually this is becoming common in all modern languages, even JavaScript!).

So, (partial map *) means exactly: take map with pre-selected first argument (*) and create a new function that uses its arguments as vectors to perform the mapping.

Upvotes: 0

johnbakers
johnbakers

Reputation: 24750

You're over-thinking it. The first argument to partial must be a function. The next arguments must be whatever would be valid arguments to that function you just named as the first argument -- including other functions, if your first parameter is a higher-order function like map or reduce or many others.

(partial map *)

The first argument is a function, map. The next argument is whatever would be a valid argument to map. Since map requires a function as its first argument, this partial expression requires a function as its second argument.

As simple as that. You can think of the * as an argument to the map first, and by extension, an argument to partial.

Upvotes: 1

Related Questions