【问题标题】:Clojure : java.lang.Character cannot be cast to clojure.lang.IFnClojure:java.lang.Character 不能转换为 clojure.lang.IFn
【发布时间】:2023-04-07 05:01:01
【问题描述】:

我只是想在 Clojure 中写一个简单的小猜谜游戏,结果出现了这个错误。我看不到一个字符在哪里被视为我的函数,因为结果输入也预测不应该有这样的问题。代码如下:

(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

【问题讨论】:

    标签: java clojure lisp


    【解决方案1】:

    错误来自试图将字符评估为函数,例如:

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

    我认为是if 语句中的额外括号试图将字符评估为函数。请记住,在 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
    

    【讨论】:

    • 我知道错误信息是什么意思,只是不知道我哪里出错了。从输出中可以看出,它仍然打印出空列表然后失败,这绝对没有意义。顺便说一下,像这样 () 标记一个空列表有什么问题?
    • 请注意,在新版本的代码中,原始代码中的空括号如何被替换为 (let ...) 表单。空括号是异常的原因。
    • 好吧,我用引号替换了所有未引用的空列表,我也尝试了向量,但我得到了同样的错误
    • 哦,是的,让我忘了那个
    • '()() 是相同的。还没有看到,如果一个序列不为空,(seq s) 就可以了。
    【解决方案2】:

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

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

    此外,您的函数会递归调用自身。这对于短游戏会话来说没问题,但对于长时间游戏会话可能会造成麻烦。在您的情况下,函数 akasztofa! 符合尾递归优化标准 (TRO),因此您可以用 recur 形式替换内部调用:

    (recur (removeEach s guess) lives)
    (recur s (- lives 1))))
    

    【讨论】:

      猜你喜欢
      • 2017-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多