2009-08-02 17 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)将返回一个空列表?