Paul
Paul

Reputation: 8182

In Clojure can I call a function that expects keys with a map?

Let's say I have

(defn test [ & {:keys [a b c]}]
   (println a)
   (println b)
   (println c))

What I want is to call test with a map {:a 1 :b 2 :c 3}.

This works:

(apply test [:a 1 :b 2 :c 3])

These do not:

(apply test {:a 1 :b 2 :c 3})
(apply test (seq {:a 1 :b 2 :c 3}))

EDIT So you can of course define the function like this also:

(defn test [{:keys [a b c]}] ; No & 
  (println a)
  (println b)
  (println c))

And then you can pass a map to it:

(test {:a 1 :b 2 :c 3})
1
2
3

When learning clojure I had missed this was possible. Nevertheless if you ever come across a function defined by me or somebody like me then knowing how to pass a map to it could still be useful ;)

Upvotes: 3

Views: 236

Answers (3)

Michiel Borkent
Michiel Borkent

Reputation: 34840

Any good reason not to define it like this in the first place?

(defn my-test [{:keys [a b c]}] ;; so without the &
   (println a)
   (println b)
   (println c))

and then call it like this?

(my-test {:a 10 :b 20 :c 30})

which outputs:

10
20
30
nil

Upvotes: 3

amalloy
amalloy

Reputation: 91927

user> (apply list (mapcat seq {:a 1 :b [2 3 4]}))
(:a 1 :b [2 3 4])

Upvotes: 4

Paul
Paul

Reputation: 8182

This works, but is inelegant:

(apply test (flatten (seq {:a 1 :b 2 :c 3})))

The reason (apply test (seq {:a 1 :b 2 :c 3})) doesn't work is that (seq {:a 1 :b 2 :c 3}) returns [[:a 1] [:b 2] [:c 3]], flatten takes care of this.

Better solutions?

Upvotes: 1

Related Questions