2011-09-13 57 views
5

來自命令式編程語言,我試圖圍繞Clojure進行研究,希望將其用於其多線程功能。
4Clojure的其中一個問題是編寫一個函數,生成一個長度爲N的斐波那契數列表,N> 1。我編寫了一個函數,但是由於我的背景有限,我希望得到一些關於是否這樣的輸入是最好的Clojure做事的方式。代碼如下:清理Clojure函數

(fn fib [x] (cond 
       (= x 2) '(1 1) 
      :else (reverse (conj (reverse (fib (dec x))) (+ (last (fib (dec x))) (-> (fib (dec x)) reverse rest first)))) 
     )) 
+1

更多的答案:http://codereview.stackexchange.com/questions/300/project-euler-problem-2-in-clojure – Jeremy

回答

4

這裏做,讓你有點置身於慵懶序列的一種方式,但它肯定不是真的計算斐波那契序列的最佳方式。

鑑於Fibonacci序列的定義,我們可以看到它是通過將相同的規則重複應用於'(1 1)的基本情況而構建的。 Clojure的功能iterate聽起來這將是很好的這樣的:

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 

所以對於我們的功能,我們想要的東西是需要到目前爲止,我們已經計算出的值,總結最近的兩次,並返回一個列表新價值和所有舊價值。

(fn [[x y & _ :as all]] (cons (+ x y) all)) 

參數列表這裏只是意味着xy必將從作爲函數的參數傳遞的列表中的前兩個值,包含前兩個之後的所有參數列表將被綁定到_,和作爲參數傳遞給函數的原始列表可以通過all來引用。

現在,iterate將返回一個無限序列的中間值,因此對於我們的情況,我們希望將它包裝在只返回我們感興趣的值的東西中;懶惰評估將會停止正在評估的整個無限序列。

(defn fib [n] 
    (nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2))) 

還要注意,這會以與您的實施相反的順序返回結果;當然,用reverse來解決這個問題很簡單。

編輯:或者確實如amalloy說,通過使用向量:

(defn fib [n] 
    (nth (iterate (fn [all] 
        (conj all (->> all (take-last 2) (apply +)))) [1 1]) 
     (- n 2))) 
+0

Clojure的不當你最終完成構建時,需要重用'反向鏈'的Common Lisp反模式,因爲它具有向右而不是向左擴展的向量。 – amalloy

+0

感謝您的詳細回覆。創建惰性列表的一個很好的例子,以及使用「nth」函數只根據需要進行評估。 – wespiserA

5

下面是斐波那契數的一個版本,我非常喜歡(我從Clojure的維基實現:http://en.wikibooks.org/wiki/Clojure_Programming

(def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq))) 

它的工作原理是這樣的:假設您已經擁有斐波那契數列的無限序列。如果你把序列的尾部,並將其添加元素,明智的你(的尾部的尾)原始序列斐波納契數列

0 1 1 2 3 5 8 ... 
1 1 2 3 5 8 ... 
----------------- 
1 2 3 5 8 13 ... 

因此你可以用這個來計算的序列。您需要兩個初始元素[0 1](或[1 1],具體取決於您開始序列的位置),然後僅添加添加元素的兩個序列。請注意,您需要這裏的懶序列。

我認爲這是最優雅的(至少對我來說)伸展實施的思想。

編輯:FIB功能

(defn fib [n] (nth fib-seq n)) 
7

最地道的「功能性」的方式很可能是創建斐波那契數的無限慵懶序列,然後提取的第n個值,即:

(take n some-infinite-fibonacci-sequence) 

以下鏈接具有產生fibonnaci序列沿着這些線路的一些非常有趣的方式:

http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci

最後這裏是另一個有趣的實施要考慮:

(defn fib [n] 
    (let [next-fib-pair (fn [[a b]] [b (+ a b)]) 
     fib-pairs (iterate next-fib-pair [1 1]) 
     all-fibs (map first fib-pairs)] 
    (take n all-fibs))) 


(fib 6) 
=> (1 1 2 3 5 8) 

它並不像簡潔,因爲它可以,但很好地說明了如何使用Clojure的解構,懶惰的序列和高階函數來解決這個問題。