jayunit100
jayunit100

Reputation: 17650

Clojure : Integer cannot cast to IFn

Im getting the dreaded * cannot be cast to IFn error with a simple mathematical function here:

(defn calc [sc1 m1 alpha beta gamma ta1 tb1 min_m1 min_tca tca_ratio x32]
        (* 
           (max(0,
                (+
                 (* alpha log(sc1)) 
                 (* beta log(m1)) 
                 (* gamma (/ ta1 tb1)) 
                 (- log(ta1) log(tb1)))))  

           (max(x32,(/ m1 min_m1)))

           (max(x32,(/ tca_ratio min_tca)))))

;;;;;;;;;;;;

The args are simply a bunch of numbers :

(calc 1 2 3 4 5 1 2 3 4 5 1)

My thoughts / My Question

Usually, when I get this error, I find it is due to

1) An extra parenthesis (i.e. when I've accidentally put an extra closure in my code) OR

2) Arguments that are misordered (obviously - a cast exception) .

My question is simply... how to fix this snippet, and optionally -- how can I defeat this common exception once and for all ? It seems that it occurs quite often in my Clojure coding expeditions, and I'm thinking maybe I still haven't got the right development style yet.

-------------------------------------------------------

UPDATE :

I've riddled my code with unregular syntax. The errors were in the internal functions, which used an java/c style function calls : for example max / log ...

Upvotes: 6

Views: 2452

Answers (4)

Alex Stoddard
Alex Stoddard

Reputation: 8344

Debugging this kind of thing benefits from using clojure.stacktrace or similar (there may be better/improved options in Clojure 1.3 that I haven't researched), see Obtain a callstack in Clojure and http://tech.puredanger.com/2010/02/17/clojure-stack-trace-repl/.

Note that *e is bound to the most recent exception at the repl.

For example:

user=> (defn broken [x] 
         (let [internal (fn [y] (y))]
           (internal x)))

user=> (broken 1) java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

user=> (use 'clojure.stacktrace)

user=> (print-stack-trace (root-cause *e) 2) java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn at user$broken$internal__1206.invoke (NO_SOURCE_FILE:2) user$broken.invoke (NO_SOURCE_FILE:3)

Upvotes: 1

Ankur
Ankur

Reputation: 33657

how can I defeat this common exception once and for all

With time and practice you will get better with dynamic typing.

Upvotes: 0

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17771

Looks to me like the offending expressions are (x32,(/ m1 min_m1)) and (x32,(/ tca_ratio min_tca)) and also the log(..) ones.

Clojure follows the standard lisp convention of having the first element of an unquoted list be a function to call. In other words, you want to have (log ...) instead of log(...) and (max ...) instead of (max (...))

Catching these errors is pretty easy in your particular style: everything that matches "XXX(" where XXX is any number of non-space, non-parenthesis characters is an error.

Upvotes: 14

Brian Cooley
Brian Cooley

Reputation: 11662

It looks to me like you have a problem with the log(sc1), etc. calls.

Ought to look (assuming log is defined somewhere) something like:

(defn calc [sc1 m1 alpha beta gamma ta1 tb1 min_m1 min_tca tca_ratio x32]
    (* 
     (max 0
          (+
           (* alpha (log sc1)) 
           (* beta (log m1)) 
           (* gamma (/ ta1 tb1)) 
           (- (log ta1) (log tb1))))  

     (max x32 (/ m1 min_m1))
     (max x32 (/ tca_ratio min_tca))))

If you just want to use the Java log, replace log with Math/log which calls the static log function in java.lang.Math

Upvotes: 6

Related Questions