У меня есть программа Clojure, которая возвращает сумму ленивой последовательности even
чисел Фибоначчи ниже n
:
(defn sum-of-even-fibonaccis-below-1 [n]
(defn fib [a b] (lazy-seq (cons a (fib b (+ b a)))))
(reduce + (take-while (partial >= n) (take-nth 3 (fib 0 1)))))
(time (dotimes [n 1000] (sum-of-even-fibonaccis-below-1 4000000))) ;; => "Elapsed time: 98.764msecs"
Это не очень эффективно. Но если я не уменьшу последовательность и просто верну список значений (0 2 8 34 144...)
, он сможет выполнять свою работу в 20 раз быстрее:
(defn sum-of-even-fibonaccis-below-2 [n]
(defn fib [a b] (lazy-seq (cons a (fib b (+ b a)))))
(take-while (partial >= n) (take-nth 3 (fib 0 1))))
(time (dotimes [n 1000] (sum-of-even-fibonaccis-below-2 4000000))) ;; => "Elapsed time: 5.145msecs"
Почему reduce
так дорого обходится эта ленивая последовательность Фибоначчи и как я могу ее ускорить, не отказываясь от идиоматического Clojure?