2009-08-02 41 views
13

我應該使用哪個更好?:(減少+ ...)或(應用+ ...)?

(apply + (filter prime? (range 1 20))) 

(reduce + (filter prime? (range 1 20))) 

編輯:這是首要Clojure中從優化工具包中的源。

(defn prime? [n] 
    (cond 
    (or (= n 2) (= n 3))   true 
    (or (divisible? n 2) (< n 2)) false 
    :else       
    (let [sqrt-n (Math/sqrt n)] 
     (loop [i 3] 
      (cond 
       (divisible? n i) false 
       (< sqrt-n i)  true 
       :else   (recur (+ i 2))))))) 
+0

[Clojure:reduce vs. apply]的可能重複(http://stackoverflow.com/questions/3153396/clojure-reduce-vs-apply)。鏈接的問題比這個更新,但它有IMO更好的答案,所以我提名它爲倖存者。 – amalloy 2012-05-29 19:14:56

回答

18

如果你問在性能方面,該reduce是一個好一點:

(time (dotimes [_ 1e6] (apply + (filter even? (range 1 20))))) 
"Elapsed time: 9059.251 msecs" 
nil 

(time (dotimes [_ 1e6] (reduce + (filter even? (range 1 20))))) 
"Elapsed time: 8420.323 msecs" 
nil 

在這種情況下,約7%的差異,但情況因人而異根據不同的機器上。

您尚未提供prime?函數的源代碼,因此我已將even?替換爲謂詞。請記住,您的運行時間可能由prime?控制,在這種情況下,reduceapply之間的選擇更爲重要。

如果你問哪一個更「lispy」,那麼我會說reduce的實現是可取的,因爲你正在做的是在功能編程意義上的減少/摺疊。

13

我認爲reduce將是可取可用時,因爲apply使用列表作爲參數傳遞給函數,但是當你有大量的 - 也就是說,一個億 - 列表中的元素,你會用一百萬個參數構造一個函數調用!這可能會導致一些Lisp實現的問題。

+6

Common Lisp有一個不斷的CALL-ARGUMENTS-LIMIT。 – 2009-08-02 19:55:34

+2

好處雖然不是Clojure的問題 - Clojure很高興以這種方式構建任意長的參數列表(即使是無限的懶惰的列表也是如此......) – mikera 2011-11-22 01:26:15

8

我期待應用來實現一個可能很醜的懶惰列表,並且你永遠不希望假設你的列表不是懶惰的,因爲你可能突然發現自己被大量的內存使用所擊中。

Reduce將逐個抓取它們,並將結果一起放入一個整體中,而不是一次將整個列表整理出來。

9

(reduce op ...)是規範和(apply op ...)例外(特別是對於str和concat)。

6

我打算扮演惡魔的擁護者,併爲apply辯論。

reduce是Clojure的從平fold(更準確地foldl),左倍,並且通常與初始元素所定義,因爲摺疊操作有兩個部分:

  • 的初始(或「零「)值

  • 操作用於組合兩個值

因此找到的作爲和數字的自然使用方式是+(fold + 0 values)或clojure,(reduce + 0 values)

這明確地顯示了一個空列表,這是非常重要的結果,因爲它並不明顯,我認爲+回報0在這種情況下 - 畢竟,+二元運算(所有fold需求或假設) 。

現在,在實踐中,事實證明,Clojure的+被定義爲比二進制運算符。它會花費很多甚至是零值。涼。但如果我們使用這個「額外」信息,它很友好,可以向讀者發信號。​​這樣做 - 它說「我使用+以一種奇怪的方式,不僅僅是一個二元運算符」。這有助於人們(至少我)理解代碼。

[有趣的是,爲什麼apply感覺更清晰。我認爲這部分是你對讀者說的:「看,+被設計爲接受多個值(這就是應用的用途),所以語言實現將包括零值的情況。」暗含的論點不適用於reduce應用於單個列表。]

或者(reduce + 0 values)也可以。但(reduce + values)在我身上觸發了一種本能的反應:「嗯,+提供了一個零?」。

,如果你不同意,那麼請你downvote或張貼回覆之前,你肯定什麼(reduce * values)將返回一個空列表?