In clojure, it is possible to destructure some keys of a map like this:
(let [{:keys [cpp js]} {:cpp 88 :js 90}]
(println js); 90
(println cpp); 88
)
Is there a way to destructure all the keys of a map?
Maybe something like:
(let [{:all-the-keys} {:cpp 88 :js 90}]
(println js); 90
(println cpp); 88
)
Clojure - Maps. A Map is a collection that maps keys to values. Two different map types are provided - hashed and sorted. HashMaps require keys that correctly support hashCode and equals. SortedMaps require keys that implement Comparable, or an instance of Comparator.
However, in Clojure 1.11 the capability was added to allow passing of alternating key→values, or a map of those same mappings, or even a map with key→values before it to functions expecting keyword arguments. Therefore, the call to configure above can take any of the following forms in addition to those shown above:
Clojure destructuring is broken up into two categories, sequential destructuring and associative destructuring. Sequential destructuring represents a sequential data structure as a Clojure vector within a let binding.
The use of keyword arguments had fallen in and out of fashion in the Clojure community over the years. They are now mostly used when presenting interfaces that people are expected to type at the REPL or the outermost layers of an API. In general, inner layers of the code found it easier to pass options as an explicit map.
Not really, and it wouldn't be a good idea. Imagine:
(let [{:all-the-keys} m]
(foo bar))
Are foo and bar globals? Locals? Keys you should extract from m? What should this code do if m sometimes contains a foo key, and foo is also a global function? Sometimes you call the global, and sometimes you call the function stored in m?
Ignoring the technical problems (which could be overcome), it is really a disaster for readability and predictability. Just be explicit about what keys you want to pull out; if you frequently want to pull out the same ten keys, you can write a simple macro like (with-person p body)
that simplifies that common case for you.
This question is pretty old so you've probably forgotten about it, but it came up on google when I was trying to do the same thing, so if I post my solution it might help someone else out.
(defmacro let-map [vars & forms]
`(eval (list 'let (->> ~vars keys
(map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
(apply concat) vec)
'~(conj forms 'do))))
This basically transforms the map {:cpp 88 :js 90}
into the binding form [cpp 88 js 90]
then constructs a let
binding, along with performing some eval-jitsu to make sure that this happens at run time.
(def test-map {:cpp 88 :js 90})
(let-map test-map
(println js)
(println cpp))
;=> 90
;=> 88
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