Oto jeden sposób z tym, że daje trochę ekspozycji na leniwe sekwencji, chociaż nie jest to na pewno bardzo optymalny sposób obliczania ciągu Fibonacciego.
Biorąc pod uwagę definicję sekwencji Fibonacciego, widzimy, że jest ona tworzona przez wielokrotne stosowanie tej samej reguły do podstawowego przypadku '(1 1)
. Funkcja Clojure iterate
brzmi jak byłoby to dobre dla:
user> (doc iterate)
-------------------------
clojure.core/iterate
([f x])
Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
Więc dla naszej funkcji którą chcemy coś, co wyraża wartości obliczonych mamy tak daleko, kwoty dwóch ostatnich, i zwraca listę nowej wartości i wszystkich starych wartości.
(fn [[x y & _ :as all]] (cons (+ x y) all))
Lista argumentów tutaj po prostu oznacza, że x
i y
będzie związany z pierwszymi dwoma wartościami z listy przekazanej jako argument danej funkcji, wykaz zawierający wszystkie argumenty po pierwszych dwóch będzie zobowiązany do _
oraz oryginalna lista przekazana jako argument do funkcji może być określona przez all
.
Teraz, iterate
zwróci nieskończoną sekwencję wartości pośrednich, więc dla naszego przypadku będziemy chcieli zawinąć ją w coś, co po prostu zwróci wartość, która nas interesuje; leniwy ewaluacja zatrzyma całą nieskończoną sekwencję podlegającą ocenie.
(defn fib [n]
(nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2)))
Należy również zwrócić uwagę, że to zwraca wynik w odwrotnej kolejności do implementacji; Naprawdę łatwo to naprawić z reverse
.
Edycja: czy rzeczywiście, jak mówi amalloy, za pomocą wektorów:
(defn fib [n]
(nth (iterate (fn [all]
(conj all (->> all (take-last 2) (apply +)))) [1 1])
(- n 2)))
więcej odpowiedzi: http://codereview.stackexchange.com/questions/300/project-euler-problem-2-in-clojure – Jeremy