Clojure: Anonymous functions using short notation and the ‘ArityException Wrong number of args (0) passed to: PersistentVector’
In the time I’ve spent playing around with Clojure one thing I’ve always got confused by is the error message you get when trying to return a vector using the anonymous function shorthand.
For example, if we want function which creates a vector with the values 1, 2, and the argument passed into the function we could write the following:
> ((fn [x] [1 2 x]) 6) [1 2 6]
However, when I tried to convert it to the shorthand ‘#()’ syntax I got the following exception:
> (#([1 2 %]) 6) clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector AFn.java:437 clojure.lang.AFn.throwArity AFn.java:35 clojure.lang.AFn.invoke NO_SOURCE_FILE:1 user/eval575[fn] NO_SOURCE_FILE:1 user/eval575
On previous occasions I’ve just stopped there and gone back to the long hand notation but this time I wanted to figure out why it didn’t work as I expected.
I came across this StackOverflow post which explained the way the shorthand gets expanded:
#() becomes (fn [arg1 arg2] (...))
which means that:
#(([1 2 %]) 6) becomes ((fn [arg] ([1 2 arg])) 6)
We are evaluating the vector [1 2 arg] as a function but aren’t passing any arguments to it. One way it can be used as a function is if we want to return a value at a specific index e.g.
> ([1 2 6] 2) 6
We don’t want to evaluate a vector as a function, rather we want to return the vector using the shorthand syntax. To do that we need to find a function which will return the argument passed to it and then pass the vector to that function.
The identity function is one such function:
> (#(identity [1 2 %]) 6) [1 2 6]
Or if we want to be more concise the thread-first (->) works too:
> (#(-> [1 2 %]) 6) [1 2 6]