【问题标题】:clojure.lang.Cons cannot be cast to Clojure.lang.Ifnclojure.lang.Cons 不能转换为 Clojure.lang.Ifn
【发布时间】:2018-04-05 22:02:13
【问题描述】:

大家好,我最近一直在尝试学习一门新语言,我偶然发现了 Clojure,它看起来是一门真正有趣的语言,因为我从未听说过函数式编程,尽管我之前使用过 JavaScript的杠杆作用,好吧,我将停止闲聊并进入问题。

我一直致力于解决https://github.com/gigasquid/wonderland-clojure-katas 以及更具体的双峰问题。我想我已经有了一个解决方案,但它向我发送了这篇文章标题上的错误。我已经阅读了有关此错误的信息,并且它似乎在您希望编译器需要一个函数但它没有时触发。这是我的解决方案的完整代码,看看您是否可以帮助我解决这个问题:

(ns doublets.solver
  (:require [clojure.java.io :as io]
            [clojure.edn :as edn]
            [clojure.set :as set]))

(def words (-> "words.edn"
               (io/resource)
               (slurp)
               (read-string)))

(defn linked-word [word word-list]
  (some #(when (= (count (set/difference (into #{} (seq %))
                                         (into #{} (seq word)))) 1) %)
        word-list))

(defn doublets [word1 word2]
  (let [n (count word1) v (cons word1 (filter #(= (count %) n)
                              (remove #{word1} words)))]
    (tree-seq #(and (linked-word (% 0) %) (not= (% 0) word2))
              #(cons (linked-word (% 0) (rest %))
                (remove #{(% 0)} (rest %))) v)))

你可以看到 cons 是一个函数,所以错误似乎不是上面描述的情况。

【问题讨论】:

  • 因为它似乎与(% 0) 的使用有关:虽然使用#(%) 对三个项目形式很好,但它很快就会变得混乱。为了可读性,您可以使用匿名 fn 来解构 args,例如:((fn [[f & r :as a]] [f r a]) [1 2 3]) for first, rest, all

标签: clojure


【解决方案1】:

下载words.edn 文件并使用(doublets "bank" "loan") 运行后,我可以重现错误。我认为问题在于这些表达方式:

 (% 0)

你在几个地方都有。我看到你是cons-ing 一些东西,所以这可能是一个线索。 (% 0) 应该做什么? 如果您想要第一个字符,只需说 (first xyz) 或其他内容。

我还会拆分匿名函数#(...) 并给它们取真实姓名。

更新

正如这个实验所示,我的猜测似乎是正确的:

(cons 1 [2 3]) => (1 2 3)
(class (cons 1 [2 3])) => clojure.lang.Cons

(vec (cons 1 [2 3])) => [1 2 3]
(class (vec (cons 1 [2 3]))) => clojure.lang.PersistentVector

好的,改写如下:

(defn doublets [word1 word2]
  (let [n (count word1)
        v (vec (cons word1 (filter #(= (count %) n)
                             (remove #{word1} words))))]
    (tree-seq
      #(and
         (linked-word (% 0) %)
         (not= (% 0) word2))
      #(vec (cons (linked-word (% 0) (rest %)))
         (remove #{(% 0)} (rest %)))
      v)))

新错误:java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol

还有我们需要的线索!

我们将事物评估为符号,而不是字符串!问题在于read-string,这是您阅读源代码的方式,而不是字符串之类的数据。删除read-string

(def words (-> "words.edn"
             (io/resource)
             (slurp)))

我们现在在这一行得到一个新的错误:

    v (vec (cons word1 (filter #(= (count %) n)
                         (remove #{word1} words))))]

ERROR in (dotest-line-40) (RT.java:664)
Uncaught exception, not in assertion.
expected: nil
  actual: java.lang.UnsupportedOperationException: 
             count not supported on this type: Character

所以你的seq 创造了类似“foo” => [\f \o \o] 的东西,然后你试着说(count \f)。你不能算一个字符,只能算一个字符串。

我会让你从那里调试它。

【讨论】:

  • 另一个提示:在通过(println ...) 等验证每个增量之后,将您的解决方案分成小块。
猜你喜欢
  • 2023-04-07
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多