Reputation: 13174
I've started to learn clojure. In my book there is following exercise:
Write a function, mapset, that works like map except the return value is a set:
(mapset inc [1 1 2 2])
; => #{2 3}
I've started with something like this:
(defn mapset
[vect]
(set vect))
The result is error
"Wrong number of args (2) passed to: core/mapset"
I tried [& args]
as well.
So, the question is: how can I solve such problem?
Upvotes: 1
Views: 754
Reputation: 13354
Take a closer look at your call to mapset
:
(mapset inc [1 1 2 2])
Since code is data, this "call" is just a list of three elements:
mapset
inc
[1 1 2 2]
When you evaluate this code, Clojure will see that it is a list and proceed to evaluate each of the items in that list (once it determines that it isn't a special form or macro), so it will then have a new list of three elements:
core/mapset
was boundclojure.core/inc
was bound[1 1 2 2]
Finally, Clojure will call the first element of the list with the rest of the elements as arguments. In this case, there are two arguments in the rest of the list, but in your function definition, you only accounted for one:
(defn mapset
[vect]
(set vect))
To remedy this, you could implement mapset
as follows:
(defn mapset
[f vect]
(set (map f vect)))
Now, when you call (mapset inc [1 1 2 2])
, the argument f
will be found to the function clojure.core/inc
, and the argument vect
will be bound to the vector [1 1 2 2]
.
Upvotes: 4
Reputation: 10682
Your definition of mapset
takes a single argument vect
At a minimum you need to take 2 arguments, a function and a sequence
(defn mapset [f xs] (set (map f xs)))`
But it is interesting to think about this as the composition of 2 functions also:
(def mapset (comp set map))
Upvotes: 4