Reputation: 1710
I've encountered a problem while I was doing a task from 4clojure.com. Here is the description of a task:
Write a function which returns the last element in a sequence.
I've solved it using the following code:
#(first (reverse %))
When I wanted to change the first
function with a number of an index.
like so:
#(0 (reverse %))
I've received an error:
java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn
My question is:
Why am I receiving this error?
I cannot get it, because for instance
([1 2 3 4] 0)
is perfectly valid and returns the first element of a sequence so why I cannot use index of an array in the function?
EDIT1:
Even the following code does not work and I suppose APersistentVector
is first there.
#((reverse %) 0)
EDIT2:
I managed to make it work by converting the list which is returned from reverse
function to vector. Thanks @Josh
(#((vec (reverse %)) 0)[1 2 3])
Upvotes: 3
Views: 264
Reputation: 4806
If you look at the code for APersistentVector, you will see:
public abstract class APersistentVector extends AFn ...
AFn
implements IFn
, which extends java's Callable
and Runnable
interfaces, which means that a clojure persistent vector can be called as a function, with the argument being used as the index to retrieve. You can see this here:
public Object invoke(Object arg1) {
if(Util.isInteger(arg1))
return nth(((Number) arg1).intValue());
throw new IllegalArgumentException("Key must be integer");
}
The same is true for maps and sets; they can all be invoked as functions:
({:a 1 :b 2} :b) ;; 2
(#{:a :b} :a) ;; :a
([1 2 3 4] 0) ;; 1
However, a Long
(your number zero) does not implement IFn
:
(ancestors (class 42))
=>
#{java.lang.Comparable
java.lang.Number
java.lang.Object
java.io.Serializable}
Hence, it cannot be invoked as a function.
Upvotes: 8