2015-05-20 4 views
3

Newbie Clojure вопрос. Каковы плюсы и минусы следующих двух способов реализации/представления последовательности Фибоначчи? (В частности, есть все, чтобы полностью исключить один или другой как плохая идея.)Clojure seq return function vs direct 'def' of seq

(ns clxp.fib 
    (:gen-class)) 

; On the one hand, it seems more natural in code to have a function that 
; returns 'a' Fibonacci sequence. 
(defn fib-1 
    "Returns an infinite sequence of Fibonnaci numbers." 
    [] 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))) 

; > (take 10 (fib-1)) 
; (0 1 1 2 3 5 8 13 21 34) 

; On the other hand, it seems more mathematically natural to define 'the' 
; Fibonacci sequence once, and just refer to it. 
(def fib-2 
    "The infinite sequence of Fibonnaci numbers." 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))) 

; > (take 10 fib-2) 
; (0 1 1 2 3 5 8 13 21 34) 

а) Каковы плюсы и минусы этих двух подходов к определению бесконечную последовательность? (Я знаю, что это несколько особый случай в том, что эта конкретная последовательность не требует никаких аргументов - в отличие, скажем, от бесконечной последовательности кратных «n», которая, по моему мнению, потребует первого подхода, чтобы указать значение «n».)

b) Есть ли какая-либо чрезмерная причина, чтобы предпочесть одну из этих реализаций другой? (Потребление памяти, применимость при использовании в качестве аргумента и т. Д.)

+0

Я бы определил 'fib-1', чтобы получить его независимо, а затем, если вы решите, что вам нужен экземпляр, не содержащий мусор, вы можете определить' fib-2' в терминах 'fib-1' 'as' (def fib-2 (fib-1)) '. –

+0

Возможно, дубликат: http://stackoverflow.com/questions/2214258/holding-onto-the-head-of-a-sequence – ClojureMostly

ответ

3

fib-2 является предпочтительным в пользу времени, если его элементы просматриваются несколько раз, потому что в ленивом seq их нужно только рассчитывать один раз.

В связи с глобальным связыванием seq вряд ли когда-либо станет сборщиком мусора, поэтому, если ваша программа пройдет через миллион фибоначчи, чтобы сделать некоторые вычисления один раз, тем более, если ему не нужно удерживать голову seqs, вызов fib-1 в локальном контексте предпочтительнее в отношении производительности пространства.

+0

Просто уточнить. Вы говорите, что 'fib-1' может быть лучше, потому что он не сохранит seq дольше, чем необходимо (потенциально экономя память за счет перерасчета seq для разных вызовов на' fib-1').Но 'fib-2' экономит перерасчет за счет отсутствия (возможно, никогда) мусора, собирающего seq. Я правильно понял? – Paul

+0

Да. Это верно. –

+0

Особенно, если вы просто выполняете итерацию, каждый обработанный элемент seq может быть немедленно собран в мусор. –

2

Это зависит от вашего использования и того, насколько важно не переваривать fib seq несколько раз. Однако из моих экспериментов ниже у меня были проблемы с def при использовании длинных последовательностей.

Если вы собираетесь ссылаться на множество элементов, то вам нужно будет следить за удержанием головы, как сказал Леон.

Это можно проиллюстрировать следующим образом (они расширяют несколько примеров из Clojure программирования):

(let [[t d] (split-with #(< % 10) (take 1e6 (fib-1)))] 
    [(count d) (count t)]) 
=> OutOfMemoryError Java heap space 

(let [[t d] (split-with #(< % 10) (take 1e6 (fib-1)))] 
    [(count t) (count d)]) 
=> [7 999993] 

Note, я должен изменить реализацию, чтобы использовать исходный вектор [0 1N] избежать ArithmeticException integer overflow при приеме больших последовательности чисел fib.

Интересно, изменение к использованию Фибо-2 вместо дает ту же ошибку ООМ для удержания головы случай, но без головы, удерживающие версии брейки:

(let [[t d] (split-with #(< % 10) (take 1e6 fib-2))] 
    [(count t) (count d)]) 
=> [7 270036] 

Последняя цифра должна быть 999993.

причина ООМ в обоих случаях, как указано в Clojure Программирование:

так как последнее обращение т не происходит до обработки д, не ссылка на голова последовательности диапазона сохраняется, и не возникает памяти .

+0

Это интересно. Я ожидал различий в характеристиках производительности; Я не ожидал, что с результатом будет какая-либо логическая/вычислительная разница в результате выбора того или другого! – Paul

+0

Я не пытался разобраться, почему это происходит не так, быть интересным, если кто-нибудь знает. –

+0

Я не могу воспроизвести неверный результат с помощью 'fib-2'. –

Смежные вопросы