Clojure:评估的返回值

时间:2012-04-01 17:20:54

标签: clojure classcastexception

* 简单问题:为什么在评估时此函数会抛出异常? *

  • 如果字符串中有重复项,则在找到副本时会抛出类别转换异常。

  • 如果字符串没有重复项,则抛出NullPointerException。

* 代码*

(defn first-duplicate-char [str-in]
      (loop [list-Rem (seq str-in) set-Seen (set [])]
        (print (type list-Rem) " " list-Rem (next list-Rem) "\n")
        (if (= 0 (count str-in))
            nil
            (if (some #(= (first list-Rem) %) set-Seen)
                (first list-Rem)
                (recur  
                    (seq (next list-Rem))
                    (conj set-Seen (first list-Rem)))))))

1 个答案:

答案 0 :(得分:2)

您的问题是(= 0 (count str-in))永远不会更改,因此您最终会尝试在first上致电nil。 [编辑:我错了,你的代码实际上是按原样运行的 - if语句只是一个无操作。我希望你无论如何都能享受这个答案的其余部分。]

相反,您应该在next的{​​{1}}上致电rest(而不是list-Rem)并直接在recur中使用list-Rem测试,使用if的属性为空seq返回nil。以下是我重写代码的方法:

next

的变化:

  • 小写名称
  • 无需在(defn first-duplicate [in] (loop [seen #{} remain (seq in)] (when-let [[head & tail] remain] (if (contains? seen head) head (recur (conj seen head) tail))))) seq
  • 的输出上致电next
  • 有集合,rest(检查是否存在密钥)比contains?更快(在元素上运行谓词,直到某些东西产生真值)
  • set literal
  • 使用some在测试失败时返回when
  • 使用nil解构并绑定第一个char并休息

文体变化:

  • 名称更改为不太具体(例如,不限于字符串)
  • 更改循环局部的顺序,使recur看起来更像结构递归
  • 将循环本地人放在不同的行上