ᐅdevrimbaris
ᐅdevrimbaris

Reputation: 796

"apply map vector" idiom - How happens to be 2 functions?

Here is a sample from my mini code where I copied from clojure docs site.

(apply map vector (vec jpgList)) 

I guess map and vector are both functions, but apply takes only one function. How come in here apply takes two functions?

Upvotes: 9

Views: 3631

Answers (4)

Mohamed
Mohamed

Reputation: 87

Consider this:

user=> (let [n1 1
  #_=>       n2 2
  #_=>       n-coll [n1 n2]]
  #_=>   (=
  #_=>    (apply + 999 n-coll)
  #_=>    (+ 999 n1 n2)))
true

'apply' applies + to the argument list formed by prepending 999 to n-coll. If you substitute map for + and vector for 999 when the collection in question is made of vectors:

user=> (let [r1 [1 2 3]
  #_=>       r2 [4 5 6]
  #_=>       r-coll [r1 r2]]
  #_=>   (=
  #_=>    (apply map vector r-coll)
  #_=>    (map vector r1 r2)))
true

Upvotes: 0

Francis Avila
Francis Avila

Reputation: 31621

apply accepts a function and its arguments. If called with more than two arguments, the middle arguments will be added as scalar arguments (like using partial). See the documentation for apply

In other words, all four of these are the same:

(apply (partial map vector) [[1 2 3 4] "abcd"])
(apply map [vector [1 2 3 4] "abcd"])
(apply map vector [[1 2 3 4] "abcd"])
(map vector [1 2 3 4] "a b c d")

All will return ([1 \a] [2 \b] [3 \c] [4 \d]).

Upvotes: 5

Alex Stoddard
Alex Stoddard

Reputation: 8344

Only map is being 'applied'. However the first argument to map is always itself a function. In this case vector is being prepended to the the sequence of arguments produced by (vec jpgList). vector here is not a second function being applied, it is the first argument in the sequence to which map is applied together with the rest.

You will see this idiom often when applying any higher order function that itself takes a function as an argument.

Upvotes: 2

Michiel Borkent
Michiel Borkent

Reputation: 34800

Read the documentation of apply:

user=> (doc apply)
-------------------------
clojure.core/apply
([f args] [f x args] [f x y args] [f x y z args] [f a b c d & args])
  Applies fn f to the argument list formed by prepending intervening arguments to args.
nil

So, (apply map vector (vec jpgList)) corresponds to f x args, so map will be applied to the the function vector, followed by the elements of (vec jpgList). Unlike Haskell, Clojure's map supports multiple collections to operate on. (vec jpgList) presumably is a nested vector, or list, like in the following example:

user=> (apply map vector [[1 2 3] [4 5 6]])
([1 4] [2 5] [3 6])  

What happened is, every element produced by map is the vector of each nth element of the elements of the nested vector. This function is also known as transpose in matrix operations.

Upvotes: 12

Related Questions