FieryCod
FieryCod

Reputation: 1710

Error while trying to get first element of sequence by index in a function call

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

Answers (1)

Josh
Josh

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

Related Questions