I'm trying to define a function that takes a map and a regular argument, and I'd like to destructure parts of the map, something like
(defn do-stuff
[[{:keys [foo bar]} where] what]
(println foo bar what))
but when I call the function I get an error
; Execution error (UnsupportedOperationException) at .../do-stuff (REPL:34).
; nth not supported on this type: PersistentArrayMap
If I swap function arguments
(defn do-stuff
[what [{:keys [foo bar]} where]]
(println foo bar what))
everything works fine. Of course I could just write a let
inside the function and do the destructuring there, but I wonder what I'm missing...
EDIT: to clarify I expect to be able to call the function like
(do-stuff {:foo "something" :bar "something else"} "baz")
Since you fail to show us, what your call there is, my guess is, that
you are confusing the let
syntax for destructuring with the one on
functions.
So the following calls work - note the nesting in a vector of the map
and the dangling where
:
(defn do-stuff
[[{:keys [foo bar]} where] what]
(println foo bar what))
(do-stuff [{:foo 1 :bar 2} 3] 4)
; 1 2 4
(defn do-stuff
[what [{:keys [foo bar]} where]]
(println foo bar what))
(do-stuff 0 [{:foo 1 :bar 2} 3])
; 1 2 0
Although you don't print where
, it seems like you want to hold on to
the map itself. But this is done via :as
.
(defn do-stuff
[{:keys [foo bar] :as where} what]
(println foo bar where what))
(do-stuff {:foo 1 :bar 2 :baz 3} 4)
; 1 2 {:foo 1, :bar 2, :baz 3} 4
The reason, why things happening as they are happening falls back to this:
Positional destructuring works for strings (it gives the character on
the position, but then the map-destructuring fails, because a char is no
map. But it fails gracefully and just assigns nil
to the two key
variables.
But when a map is provided instead it fails hard, because they can not
destructured positionally (accessed via nth
), hence the error message.
(defn do-stuff
[[{:keys [foo bar]}]]
(println foo bar))
(do-stuff "baz")
; nil nil
(do-stuff {:foo "something" :bar "something else"})
; throws