Проблема с функцией Clojure - PullRequest
3 голосов
/ 23 мая 2010

каждый, я вчера начал работать над проектом Эйлера в 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)))))))))

Я пытаюсь запустить его так:

(find-max-palindrom-in-range 100 1000)

и я получаю это исключение:

java.lang.Integer cannot be cast to clojure.lang.IFn
  [Thrown class java.lang.ClassCastException]

, который я предполагаю, означает, что в каком-то месте я пытаюсь оценить Integer как функцию. Однако я не могу найти это место, и меня больше всего удивляет то, что все работает, если я просто оцениваю это так:

(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 и новейший SLIME от ELPA.

Редактировать: Вот код для 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)))))))

1 Ответ

6 голосов
/ 23 мая 2010

Код работает на моем REPL (1.1). Я бы посоветовал вам вставить его обратно в свой и попробовать еще раз - возможно, вы просто что-то опечатали?

Сказав это, вы можете использовать это как возможность сделать код проще и более очевидно правильным. Некоторый низко висящий фрукт (не читайте, если вы думаете, что это может отнять у вас удовольствие от Project Euler, хотя с вашей логикой, уже записанной, я думаю, что это не должно):

  1. Вам не нужно помещать is-palindrome? в анонимную функцию, чтобы передать его в filter. Просто напишите (filter is-palindrome? ...).

  2. То, что loop в is-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))
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...