There's something I must be missing about the threading macro in Clojure.
I have a map with values that are maps as well, and I'd like to a lookup in the result of another lookup. Let the map be a simple {:a {:b 2}}
-- first I want to look up the key :a
, that's going to yield {:b 2}
, then look up b
, the result is 2
. The key for the second lookup needs to be a result of a function.
((fn [x] (get x :b)) ({:a {:b 2} } :a ))
=> 2
Ok, let's make it more readable with the threading macro.
(-> {:a {:b 2} } :a (fn [x] (get x :b)))
I.e. apply :a
as a function on the map then apply another function. Well, this doesn't work:
CompilerException java.lang.IllegalArgumentException: Parameter declaration :a should be a vector
Oddly enough, if the anonymous function is extracted to a named one, then it works fine:
(defn f [x] (get x :b))
(-> {:a {:b 2} } :a f)
=> 2
Or even:
(def f (fn [x] (get x :b)) )
(-> {:a {:b 2} } :a f)
=> 2
Why is there a difference between how named and anonymous functions work?
The threading macro sees, and alters, each subform in the series before that form is evaluated, by recursively inserting the prior form as the first argument to each subform.
you start with:
(-> {:a {:b 2} } :a (fn [x] (get x :b)))
this becomes:
(-> (:a {:a {:b 2}}) (fn [x] (get x :b)))
this becomes:
(fn (:a {:b {:b 2}}) [x] (get x :b)))
Which is clearly not what you wanted at all.
But let's see what happens if you add extra parens around the anonymous function:
(-> {:a {:b 2}} :a ((fn [x] (get x :b))))
(-> (:a {:a {:b 2}}) ((fn [x] (get x :b))))
(-> ((fn [x] (get x :b)) (:a {:a {:b 2}})))
((fn [x] (get x :b)) (:a {:a {:b 2}}))
At the last recursive macroexpansion of the ->
form we are now left with valid code that does what you want.
To complement noisesmith's response, in this particular case you don't need the threading macro. The idiomatic way to get a value from a nested map is get-in
. e.g:
(get-in {:a {:b 2}} [:a :b])
=>
2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With