Последовательность Фибоначчи с использованием цикла и повторения

Я выполняю задачу Project Euler в Clojure и хочу найти сумму всех четных чисел в последовательности Фибоначчи до определенного числа.

Код функции, которая это делает, приведен ниже. Я знаю, что есть более быстрые и простые способы сделать это, я просто экспериментирую с рекурсией, используя цикл и повторение. Однако код, похоже, не работает, он никогда не возвращает ответ.

(defn fib-even-sum [upto]
  (loop [previous 1 nxt 1 sum 0]
    (if (or (<= upto 1) (>= nxt upto))
     sum)
    (if (= (mod nxt 2) 0)
       (recur nxt (+ previous nxt) (+ sum nxt))
       (recur nxt (+ previous nxt) sum))))

Я не был уверен, смогу ли я повторяться дважды в одном и том же цикле или нет. Я не уверен, что это вызывает проблему?


person adamjmarkham    schedule 23.06.2011    source источник
comment
Я изучал этот предикат. Я собираюсь изменить код, чтобы использовать его. Спасибо, что указали на это.   -  person adamjmarkham    schedule 23.06.2011
comment
есть fibs в 'clojure.contrib.lazy-seqs, что довольно быстро. При этом задача может быть выражена следующим образом: (reduce + (filter #(even? %) (take-while #(< % 4000000) (fibs)))) .. некоторые другие задачи Эйлера также можно решить в виде одной строки, наслаждайтесь! :-)   -  person klang    schedule 24.06.2011
comment
Просто альтернатива (знайте, что вы ее не искали, так что она в комментарии!) (def fibo (map second (iterate (fn [[x y]] [y (+ x y)]) [0 1])))   -  person Isaac    schedule 26.06.2011
comment
@IsaacHodes Да, не делай этого. Если вы определите его на верхнем уровне, он никогда не сможет получить GCed. Вместо этого (defn fib0 [] (map ...)) и вызовите fib0 всякий раз, когда вам нужна новая копия последовательности.   -  person amalloy    schedule 28.11.2011


Ответы (1)


У вас есть неуместная закрывающая скобка в первом IF (после sum)...

(defn fib-even-sum [upto]
  (loop [previous 1 nxt 1 sum 0]
    (if (or (<= upto 1) (>= nxt upto))
        sum
        (if (= (mod nxt 2) 0)
           (recur nxt (+ previous nxt) (+ sum nxt))
           (recur nxt (+ previous nxt) sum)))))

Теперь работает и быстро

person Paul Lam    schedule 23.06.2011
comment
Спасибо. Я вижу проблему. Отлично работает сейчас. - person adamjmarkham; 23.06.2011
comment
Между прочим, это обычная проблема для начинающих программистов на Лиспе. Если бы я писал это, я бы заменил шаблон (if a x (if b y z)) на использование cond: (cond a x, b y, :else z). Но, конечно, вы должны учиться в своем собственном темпе и не беспокоиться о форме, если вы все еще изучаете функцию. - person amalloy; 24.06.2011