各位,我昨天开始在 Clojure 中进行 Euler 项目,我的解决方案之一出现了问题,我无法弄清楚。
我有这个功能:
(defn find-max-palindrom-in-range [beg end]
(reduce max
(loop [n beg result []]
(if (>= n end)
result
(recur (inc n)
(concat result
(filter #(is-palindrom? %)
(map #(* n %) (range beg end)))))))))
我尝试像这样运行它:
(find-max-palindrom-in-range 100 1000)
我得到了这个异常:
java.lang.Integer cannot be cast to clojure.lang.IFn
[Thrown class java.lang.ClassCastException]
我认为这意味着在某个地方我试图将整数评估为函数。然而,我找不到这个地方,更让我困惑的是,如果我简单地这样评估它,一切都会正常:
(reduce max
(loop [n 100 result []]
(if (>= n 1000)
result
(recur (inc n)
(concat result
(filter #(is-palindrom? %)
(map #(* n %) (range 100 1000))))))))
(我刚刚删除了函数定义并用常量替换了参数)
提前感谢您的帮助,很抱歉我可能因我的愚蠢错误而打扰您。顺便说一句,我正在使用 Clojure 1.1 和 ELPA 的最新 SLIME。
编辑:这是is-palindrom?的代码。我已将其实现为数字的文本属性,而不是数字属性。
(defn is-palindrom? [n]
(loop [num (String/valueOf n)]
(cond (not (= (first num) (last num))) false
(<= (.length num) 1) true
:else (recur (.substring num 1 (dec (.length num)))))))
最佳答案
该代码可以在我的 REPL (1.1) 上运行。我建议您将其粘贴回您的位置并重试 - 也许您只是输错了某些内容?
话虽如此,您可以以此为契机使代码更简单、更明显正确。一些唾手可得的成果(如果您认为它会剥夺您的欧拉计划的乐趣,请不要阅读,尽管您的逻辑已经写下来,我认为它不应该):
您不需要将
is-palindrome?
包装在匿名函数中以将其传递给filter
。只需编写(filter is-palindrome? ...)
即可。is-palindrome?
中的循环
非常复杂。此外,它并不是特别高效(first
和last
都首先从字符串中生成seq
,然后是last
需要遍历所有内容)。(require '[clojure.contrib.str-utils2 :as str])
并使用(= num (str/reverse num))
会更简单、更快。既然我提到了效率,以这种方式使用
concat
有点危险——它会创建一个惰性序列,如果你堆积两个多级别的惰性(这在 Euler 4 的上下文中并不重要,但最好记住这一点)。如果您确实需要将向量向右延伸,最好选择into
。为了进一步简化事情,您可以考虑将它们分解为一个函数来过滤给定的序列,以便只保留回文,以及一个单独的函数来返回两个三位数的所有乘积。后者可以通过例如来完成
(for [f (range 100 1000) s (range 100 1000) :when (<= f s)] ; avoid duplication of effort (* f s))
关于clojure - Clojure函数的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2890850/