Подтвердить что ты не робот

В чем разница между функцией Clojure (nth [coll index]) и композицией (последняя (возьмите индексный столбец))

Я пытаюсь работать через книгу Стюарта Халлоуэя "Программирование Clojure. Весь этот функциональный материал для меня очень новый.

Я понимаю, как

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))

генерирует последовательность Фибоначчи лениво. Я не понимаю, почему

(last (take 1000000 (fibo)))

работает, а

(nth (fibo) 1000000)

выбрасывает OutOfMemoryError. Может ли кто-нибудь объяснить, как эти два выражения отличаются? Является ли (nth) каким-то образом удерживающим головку последовательности?

Спасибо!

4b9b3361

Ответ 1

Я думаю, вы говорите о проблеме, которая обсуждалась в группе google, а Rich Hickey предоставил патч, который решил проблему. И книга, опубликованная позже, не охватывала эту тему.

В clojure 1.3 ваш пример nth работает с незначительными улучшениями в функции fibo. Теперь, из-за изменений в 1.3, мы должны явно помечать M для использования произвольной точности, или она падает с throwIntOverflow.

(defn fibo[]
  (map first (iterate (fn [[a b]] [b (+ a b)]) [0M 1M])))

И с этими изменениями

(nth (fibo) 1000000)

преуспеть (если у вас достаточно памяти)

Ответ 2

Какую версию Clojure вы используете? Попробуйте (clojure -version) на repl. Я получаю одинаковые результаты для обоих выражений в 1.3.0, а именно: переполнение целых чисел.

Для

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+ a b)]) [(bigint 0) 1])))

Я получаю правильные результаты для обоих выражений (действительно большое целое число...).

Ответ 3

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

Глядя на исходный код для nth в https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java, он не похож ни на n-ое, ни на взятие, сохраняя голову.

Однако n-й использует индексирование с нулевым индексом, а не число по числу. Ваш код с n-м выбирает элемент 1000001st последовательности (тот, который указан в индексе 1000000). Вы кодируете с помощью take, возвращает конечный элемент в последовательности элементов 1000000. То, что элемент с индексом 999999. Учитывая, как быстро растет волокно, этот последний элемент может быть тем, который сломал верблюда.

Кроме того, я проверял источник 1.3.0. Возможно, более ранние версии имели разные реализации. Чтобы ваше фибо было нормально работать в 1.3.0, вам необходимо использовать арифметические функции, которые будут способствовать присвоению чисел бонусам:

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+' a b)]) [0 1])))