2015-02-09 74 views
2

您好我對Clojure/Lisp編程有點新,但我曾經在C語言中使用過遞歸,我寫了下面的代碼將所有可以除以三的數字相加1 100 在Clojure中遞歸地總結所有的三倍數Clojure

(defn is_div_by_3[number] 
    (if(= 0 (mod number 3)) 
    true false) 
) 

(defn sum_of_mult3[step,sum] 
    (if (= step 100) 
    sum 
    ) 
    (if (is_div_by_3 step) 
    (sum_of_mult3 (+ step 1) (+ sum step)) 
    ) 
) 

之間

我的想法是,當步長達到總和結束遞歸,那麼我將有我需要的和可變的,我回報倍數,但我的REPL似乎兩個返回nil變量這裏可能是錯誤的嗎?

+0

我自己是一個學習者(而不僅僅是對你的吸引),只是迭代三次的倍數不會更有效嗎?例如比如'(reduce +(take-while#(<%100)(iterate(partial + 3)0)))'。 – cfrick 2015-02-09 18:06:42

回答

1

這段代碼有幾個問題。

1)您的第一個ifsum_of_mult3是一個noop。它返回的任何內容都可以影響該函數的執行。

2)第二個ifsum_of_mult3只有一個條件,直接遞歸,如果步驟是3的倍數。對於大多數數字,第一個分支將不會被採取。第二個分支只是一個隱含的nil。無論輸入如何,你的函數都能保證返回(即使提供的第一個參數是三的倍數,下一個重現值不會)。 3)在可能的情況下,使用recur而不是自我調用,自我調用消耗堆棧,recur編譯爲不消耗堆棧的簡單循環。

最後,一些作風問題:

1)始終把與他們正在縮小塊的同一行關閉的括號。這使得Lisp樣式代碼更具可讀性,而且如果我們大多數人都沒有閱讀過Algol樣式代碼,並且將Parens放在正確的位置,這會提醒我們我們正在閱讀哪種語言。

2)(if (= 0 (mod number 3)) true false)相同(= 0 (mod number 3)這又是相同的(zero? (mod number 3))

3)使用的(inc x)代替(+ x 1)

4),用於兩個以上的潛在動作,使用casecond,或condp

(defn sum-of-mult3 
    [step sum] 
    (cond (= step 100) sum 
     (zero? (mod step 3)) (recur (inc step) (+ sum step)) 
     :else (recur (inc step) sum)) 
4

if表達不是陳述if的結果始終是其中的一個分支。事實上,Clojure沒有陳述如下:here

Clojure程序由表達式組成。每個沒有被特殊格式或宏特別處理的表單都被編譯器視爲一個表達式,它被評估爲產生一個值。沒有聲明或陳述,儘管有時可能會評估表達式的副作用並忽略它們的值。

有一個很好的在線(免費)的書,適合初學者:http://www.braveclojure.com

其他的事情,的Lisp括號並不等同於在C家族語言中的大括號。例如,我會寫你的is_div_by_3功能:

(defn div-by-3? [number] 
    (zero? (mod number 3))) 

我也將用更地道的方式爲sum_of_mult3功能:

(defn sum-of-mult-3 [max] 
    (->> (range 1 (inc max)) 
     (filter div-by-3?) 
     (apply +))) 

我認爲這個代碼是在它的意圖更富於表現力然後是遞歸版本。唯一的技巧是->>線程最後的宏。請看this answer以獲取線程最後一個宏的解釋。

+0

迂腐觀察:你不需要你的範圍從1開始,而不是默認值0. – 2015-02-09 23:39:26

+0

@DiegoBasch我知道,我這麼做是因爲我認爲它會更清楚。 – 2015-02-09 23:47:14

0

除了羅德里戈的回答,這是我第一個想到解決問題的方法e問題:

(defn sum-of-mult3 [n] 
    (->> n 
     range 
     (take-nth 3) 
     (apply +))) 

這應該是不言自明的。下面是不使用序列更「數學」的方式,考慮到所有數字多至N個包容性的總和(N *(N + 1))/ 2。

(defn sum-of-mult3* [n] 
    (let [x (quot (dec n) 3)] 
    (* 3 x (inc x) 1/2))) 

像羅德里戈說,遞歸不是這項任務的正確工具。