2012-12-21 93 views
6

我發現下面的代碼(在this blog post,解決了Coin Changer Kata):請給我解釋一下下面的Clojure代碼

(defn change-for [amount] 
    (let [denominations [25 10 5 1] 
     amounts (reductions #(rem %1 %2) amount denominations) 
     coins (map #(int (/ %1 %2)) amounts denominations)] 
    (mapcat #(take %1 (repeat %2)) coins denominations))) 

我覺得困難的部分是(reductions #(rem %1 %2) amount denominations)

正如我發現,reductions只是增量計算基於某個給定的所得徵收。例如:(reductions + [1 2 3])給出[1 3 6]

1   ; first element 
1 + 2  ; second element 
1 + 2 + 3 ; third element 

下一個計算餘數的函數rem仍然非常容易理解。

理解代碼的其餘部分我試過如下:

; first try, to see if this call works 
; outside the original code (the change-for function) 
(reductions #(rem %1 %2) 17 [10 5 1]) ; --> [17 7 2 0] 

; tried to use the reductions which takes only one argument 
; notice that 17 is now inside the array 
(reductions #(rem %1 %2) [17 10 5 1]) ; --> [17 7 2 0] 

; further simplified the expression 
(reductions rem [17 10 5 1]) ; --> [17 7 2 0] 

的最後一步是在this blog post描述刪除匿名函數。

在這裏,事情變得混亂(至少對我來說):rem需要2個參數,我不明白它如何使用數組[17 10 5 1]時如何應用它們。我嘗試了以下電話:

(rem [17 10 5 1]) ; --> gives error 
(rem [17 10 5 1] [17 10 5 1]) ; --> also gives error 
(rem 17 10) ; --> works, but how do you use it with collections? 

有人能解釋我,這rem功能與reductions功能是如何工作的?

我不太明白的另一件事是:這些百分比參數是如何應用的(在#(rem %1 %2))?我的意思是他們來自哪裏?我嘗試通過以下方式撥打rem,但出現錯誤:(#(rem %1 %2) 17 [10 5 1])。必須有一些reductions函數在幕後進行這項工作,對吧?

起初我以爲#(rem %1 %2)是一套。這些都是以類似的方式爲集合聲明的,很容易被濫用(有人剛開始使用Clojure):

(type #{1 2 3}) ; --> clojure.lang.PersistentHashSet 
(type #(1 2 3)) ; --> user$eval12687$fn__12688 

有人點我到一個網站/書籍/任何解釋Clojure的技巧如「匿名函數的特殊形式」?大多數資源只是給出了最簡單的構造(與所有其他lisp派生類似的構造),而沒有涉及Clojure的複雜性。我發現a site看起來不錯(也解釋了我上面提到的匿名函數)。 任何其他此類資源?

回答

5

此:

(reductions #(rem %1 %2) amount denominations) 

等效於此:

(reductions rem amount denominations) 

和你注意到

(reductions function start collection) 

返回的減少collectionfunction的中間結果的序列(以start作爲f第一步減少的第一個論點)。 function必須帶兩個參數。

這樣的結果:

(reductions function start [1 2 3 4 5]) 

((function start 1) (function (function start 1) 2) ...) 

#(rem %1 %2)語法僅僅是定義匿名函數,它接受兩個參數(%1%2)的簡寫,他們呼籲rem和返回結果。

它等同於:

(fn [a b] (rem a b))