Call me crazy but the Clojure reader's "dispatch" macro (#
) might be a bit overloaded.
Without going into too much detail, this macro enables the definition of:
- Set literals (
#{1 2 3}
) - Regex Patterns (
#"\d+"
) - Var-quoting (
#'x
) - Anonymous function literal (
#(...)
) - Ignore next form (
#_
)
Seems a bit sloppy...
Why the rant? Well, I was trying to return a collection literal from an anonymous function:
(map #({% 1}) c)
...but was getting the following, somewhat unhelpful, error:
user=> (map #({% 1}) [:a :b :c])
Error printing return value (ArityException)...
Wrong number of args (0) passed to: clojure.lang.PersistentArrayMap
It turns out that you can't return a collection literal of any kind from an anonymous function literal. So this also fails:
(user=> (map #([%]) [:a :b :c])
Error printing return value (ArityException)...
Wrong number of args (0) passed to: clojure.lang.PersistentVector
As does this:
(user=> (map #(#{%}) [:a :b :c])
Error printing return value (ArityException)...
Wrong number of args (0) passed to: clojure.lang.PersistentHashSet
Due to the limitations of the reader macro you either have use the fn
form:
user=> (map (fn [i] {i 1}) [:a :b :c])
({:a 1} {:b 1} {:c 1})
...or, slip in a do
form:
user=> (map #(do {% 1}) [:a :b :c])
({:a 1} {:b 1} {:c 1})
:(
Maybe this isn't a direct result of the dispatch reader macro being overloaded, it's just a limitation baked into the way that part of the macro is implemented. Whatever the reason, at least you now know how to return collection literals from an anonymous function.
Idea!
I just realized that an even better approach in cases like this one, where your 'mapping' function returns a literal, would be to use a list comprehension!
user=> (for [i [:a :b :c]] {i 1})
({:a 1} {:b 1} {:c 1})
:)
You might be wondering why I want to convert a collection to a map where all the items from the collection map to the value 1
. Well, stay tuned for the [exciting] conclusion in the next post...