Clojure:java.lang.Character无法强制转换为clojure.lang.IFn

时间:2017-12-17 19:52:07

标签: java clojure lisp

我只想在Clojure中编写一个简单的小猜谜游戏,我收到了这个错误。我无法看到Character在哪里被视为我的函数,因为结果输入也预测不应该存在这样的问题。这是代码:

(ns clojure.examples.hello
  (:gen-class))

(ns clojure-noob.core)

(defn takeFst [x n]
    (if (= n 0) () (cons (first x) (takeFst (rest x) (- n 1))))
)

(defn createSeq [elem n]
    (if (= n 0) () (cons elem (createSeq elem (- n 1))))
)

(defn fnEquals? [n]
    (fn [elem] (= elem n))
)

(defn removeEach [x elem]
    (remove (fnEquals? elem) x)
)

(defn containsString? [s ch]
    (not (empty? (filter true? (map = (createSeq ch (count s)) s))))
)

(defn akasztofa! [s lives]
    (println s)
    (if (and (not= () s) (not= lives 0))
        (
            (def guess (eval (read)))
            (if (containsString? s guess) (akasztofa! (removeEach s guess) lives) (akasztofa! s (- lives 1)))
        )
        ()
    )
)

(akasztofa! "hab" 10)

我得到的输出是:

hab
(a b)
(b)
() 
Exception in thread "main" java.lang.ClassCastException: 
java.lang.Character cannot be cast to clojure.lang.IFn, compiling:
(/home/cicaharcos/Documents/Clojure/First/akasztofa/main.clj:38:1)

我的输入是:\ h \ a \ b

2 个答案:

答案 0 :(得分:2)

错误来自于尝试将角色评估为函数,例如:

(\a) => Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.Character cannot be cast to clojure.lang.IFn, 

我认为if语句中的额外parens试图将角色评估为函数。请记住,在Clojure中,括号不是"分组"就像在Java中一样,它们意味着"函数调用"。

您的代码还有其他一些问题,值得注意的是使用()作为空列表。您必须像这样引用列表:

'()

或者,更好的是,使用带方括号的空向量(不需要引用):

 []

如果您使代码看起来如下所示,它似乎有效:

(ns clojure.examples.hello
  (:gen-class))

(ns clojure-noob.core)

(defn takeFst [x n]
    (if (= n 0) [] (cons (first x) (takeFst (rest x) (- n 1))))
)

(defn createSeq [elem n]
    (if (= n 0) [] (cons elem (createSeq elem (- n 1))))
)

(defn fnEquals? [n]
    (fn [elem] (= elem n))
)

(defn removeEach [x elem]
    (remove (fnEquals? elem) x)
)

(defn containsString? [s ch]
    (not (empty? (filter true? (map = (createSeq ch (count s)) s))))
)

(defn akasztofa! [s lives]
    (println s)
    (if (and (not= [] s) (not= lives 0))
        (let [guess (eval (read))]
          (if (containsString? s guess)
            (akasztofa! (removeEach s guess) lives)
            (akasztofa! s (- lives 1))))
        [] ))

(akasztofa! "hab" 10)

结果:

hab
\h      ; <= user input plus <ret>
(a b)
\a      ; <= user input plus <ret>
(b)
\b      ; <= user input plus <ret>
()

重新清空列表:

使用count功能,您可以看到问题:

demo.core=> (count ())
0

demo.core=> (count (\b))

ClassCastException java.base/java.lang.Character cannot be cast to clojure.lang.IFn  demo.core/eval16682 (form-init2403719904611886388.clj:1)

demo.core=> (count (1))

ClassCastException java.base/java.lang.Long cannot be cast to clojure.lang.IFn  demo.core/eval16686 (form-init2403719904611886388.clj:1)

demo.core=> (count '(\b))
1

所以你可以使用()(不带引号)作为一个空列表(我忘记了),但如果它是非空的,它会失败,除非你引用它。使用向量更简单,更不容易出错:

demo.core=> (count [])
0
demo.core=> (count [\b])
1
demo.core=> (count [1])
1

答案 1 :(得分:2)

您正在尝试将角色评估为函数。您应该避免在代码中使用eval。相反,使用来自read函数的符号列表。这比评估用户的输入要安全得多。

不要在函数内部使用def,只能在模块顶部使用Deflet在整个命名空间中全局声明一个新实体。使用akasztofa!形式创建一个本地范围,其变量存在,直到评估存在。

此外,您的函数以递归方式调用自身。对于短暂的比赛来说,这是好的,但可能会导致长期比赛的麻烦。在您的情况下,函数recur符合尾递归优化标准(TRO),以便您可以用(recur (removeEach s guess) lives) (recur s (- lives 1)))) 形式替换内部调用:

Promise.catch