Целочисленные переполнения, используя ленивые последовательности в Clojure
Я только учусь использовать ленивые последовательности в Clojure, и я не уверен, что я делаю неправильно в следующем коде:
(defn sum [seqn]
(reduce + seqn))
(defn fib
([] (concat [0 1] (fib 0 1)))
([a b] (lazy-seq (cons (+ a b) (fib b (+ a b))))))
(defn up-to [n seqn]
(filter (fn [x] (< x n)) seqn))
(sum (up-to 100 (fib))) => ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1388)
Суммируемые числа не должны быть больше 100
, так что же вызывает переполнение целого числа?
2 ответа:
Фильтрация бесконечного seq производит бесконечный seq и уменьшение по этому поводу заставляет фильтр продолжать искать другой соответствующий элемент даже после того, как предикат перестает возвращать true.
Заменить
filter
наtake-while
. Бесконечная последовательность, порожденная(fib)
, заставитfilter
бежать вечно, но перед этим она сломается из-заArithmeticException
, которое вы испытываете.take-while
остановит дальнейшее вычисление списка после того, как предикат(fn [x] (< x n))
примет значение false.(defn up-to [n seqn] (take-while (fn [x] (< x n)) seqn)) (sum (up-to 100 (fib))) ;; => 232