Clojure功能有问题

Boz*_*sov 3 clojure

大家好,我昨天开始在Clojure的欧拉项目上工作,我的一个解决方案有一个问题,我无法弄清楚.

我有这个功能:

(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)))))))))
Run Code Online (Sandbox Code Playgroud)

我尝试像这样运行它:

(find-max-palindrom-in-range 100 1000)
Run Code Online (Sandbox Code Playgroud)

我得到这个例外:

java.lang.Integer cannot be cast to clojure.lang.IFn
  [Thrown class java.lang.ClassCastException]
Run Code Online (Sandbox Code Playgroud)

我认为这意味着在某个地方我试图将整数作为一个函数进行评估.然而,我找不到这个地方,更让我感到困惑的是,如果我只是像这样评价它,一切都有效:

(reduce max
          (loop [n 100 result []]
            (if (>= n 1000)
              result
              (recur (inc n)
                     (concat result
                             (filter #(is-palindrom? %)
                                     (map #(* n %) (range 100 1000))))))))
Run Code Online (Sandbox Code Playgroud)

(我刚刚删除了函数定义并用常量替换了参数)

在此先感谢您的帮助,对不起,我可能会因为我的愚蠢错误而烦扰您.顺便说一句,我正在使用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)))))))
Run Code Online (Sandbox Code Playgroud)

Mic*_*zyk 6

该代码适用于我的REPL(1.1).我建议你把它粘贴在你的身上再试一次 - 也许你只是错误的输入了什么?

话虽如此,您可以将此作为一个使代码更简单,更明显正确的机会.一些低调的果实(如果你认为它可能会剥夺你的Project Euler乐趣,请不要阅读,尽管你的逻辑已写下来我认为它不应该):

  1. 您不需要包装is-palindrome?匿名函数来将其传递给filter.只需写下来(filter is-palindrome? ...).

  2. loopis-palindrome?相当复杂的.而且,它不是特别有效(first并且last两者seq首先从字符串中删除,然后last需要遍历所有字符串).这将是更简单,更快(require '[clojure.contrib.str-utils2 :as str])和使用(= num (str/reverse num)).

  3. 因为我提到效率,concat以这种方式使用有点危险 - 它会产生一个懒惰的seq,如果你堆积两个级别的懒惰可能会爆炸(这在Euler 4的背景下无关紧要,但它对于记在心上).如果你真的需要向右扩展向量,请选择into.

  4. 为了进一步简化,您可以考虑将它们拆分为一个函数来过滤给定的序列,以便只保留回文并且使用单独的函数来返回两个三位数字的所有产品.后者可以用例如完成

    (for [f (range 100 1000)
          s (range 100 1000)
          :when (<= f s)] ; avoid duplication of effort
      (* f s))
    
    Run Code Online (Sandbox Code Playgroud)