Reputation: 31
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
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
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
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
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