qed
qed

Reputation: 23154

"clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn" error in macro

Here is the code:

(defmacro cond2 [& body]
  (when body
    `(if ~(first body)
       ~(if (next body)
          (second body)
          (throw (IllegalArgumentException. "error")))
       ~(cond2 (next (next (body)))))))
(cond2 (> 2 1) (println "2 > 1")
       :else   (println "2 <= 1"))

I got this error:

CompilerException java.lang.ClassCastException: clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn, compiling:(/Users/personal_config_bin_files/workspace/cina/src/cina/ref_types.clj:1:24) 

If I remove the recursive part, the error goes away:

(defmacro cond2 [& body]
  (when body
    `(if ~(first body)
       ~(if (next body)
          (second body)
          (throw (IllegalArgumentException. "error")))
       )))

this only works for a body with two clauses, of course.

If I quote the recursive part like this:

(defmacro cond2 [& body]
  (when body
    `(if ~(first body)
       ~(if (next body)
          (second body)
          (throw (IllegalArgumentException. "error")))
       `(cond2 ~(next (next body))))))

then I get a different error:

CompilerException java.lang.RuntimeException: No such var: cina.ref-types/body, compiling:(/Users/personal_config_bin_files/workspace/cina/src/cina/ref_types.clj:331:5) 

Using cons instead of syntax-quote works:

(defmacro cond2 [& body]
  (when body
    `(if ~(first body)
       ~(if (next body)
          (second body)
          (throw (IllegalArgumentException. "error")))
       ~(cons 'cond2 (next (next body))))))
(cond2 (> 2 3) (println "good")
       :else   (println "bad"))

But I don't know what the difference is. Could anyone explain?

Upvotes: 1

Views: 1425

Answers (2)

qed
qed

Reputation: 23154

It's unquote-splice that I need here:

(defmacro cond2 [& body]
  (when body
    `(if ~(first body)
       ~(if (next body)
          (second body)
          (throw (IllegalArgumentException. "error")))
       (cond2 ~@(next (next body))))))

Upvotes: 1

bsvingen
bsvingen

Reputation: 2759

The problem is the (body) in your original recursive part - it tries to call body as a function, and then complains that it cannot cast the seq to a function.

Do (next (next body)) instead, and it should work fine.

Upvotes: 0

Related Questions