Reputation: 2489
I define a function, which takes two parameters - map and a key. The key is referenced from the map parameter decomposition
(defn myfunc [{v k} k]
v)
when I call:
(myfunc {:a 10} :a)
It surprisingly produces expected result: 10
Similar thing in the let:
(let [{v k} {:a 10} k :a] v)
fails, because k is not defined at the moment, when first part is evaluated.
My question is: why decomposition inside function parameters behaves differently compared to decomposition in let expressions?
Upvotes: 5
Views: 842
Reputation: 8182
Macroexpanding the defn
form I get the equivalent of this (removed .withMeta stuff and reformatted):
(def myfunc
(fn* myfunc
([p__11393 k]
(let* [map__11394 p__11393
map__11394 (if (seq? map__11394)
(apply hash-map map__11394)
map__11394)
v (get map__11394 k)]
v))))
So here we can see that the {v k}
map is in fact first assigned to a local variable p__11393
. Then the if
statement tests if that variable is in fact a sequence and turns it into a hash-map if so, otherwise leaves it as it is. Importantly, the value assigned to k
is looked up in the map after all of this happens, thus this works without error (and also would if :a
wasn't in the map, get
returns nil
in that case).
On the other hand macroexpanding the let
form I get
(let*
[map__11431
{:a 10}
map__11431
(if (seq? map__11431) (apply hash-map map__11431) map__11431)
v
(get map__11431 k)
k
:a]
v)
and here we can see that v
gets the result of (get map__11431 k)
, but k
isn't defined at this point yet, hence the error.
Upvotes: 3
Reputation: 25269
This isn't a complete answer, but the following does work:
user=> (defn myfunc [{v k} k] v)
#'user/myfunc
user=> (myfunc {:a 10} :a)
10
user=> (let [k :a {v k} {:a 10}] v)
10
user=>
Upvotes: 0