2009-08-02 19 views
13

は私が編集どちらが良いですか?:(reduce + ...)または(apply + ...)?

(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

答えて

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

applyは関数の引数としてリストを使用するので、reduceが利用可能なときには好ましいと思うでしょうが、リスト内に数百万の要素があると、 100万の引数を持つ関数呼び出しを構築する! Lispの実装によってはいくつか問題が生じるかもしれません。

+6

Common Lispには一定のCALL-ARGUMENTS-LIMITがあります。 –

+2

Clojureには問題はありませんが、Clojureはこのように任意の長い引数リストを作成することに満足しています(無限の怠け者も発生します...) – mikera

8

醜いリストを実現するのに当てはまると思いますが、リストが怠け者ではないと思われることは決してありません。なぜなら、突然大量のメモリを使用して自分自身が殴られてしまうことがあるからです。

Reduceは、それらを1つずつ取り込み、結果をまとめて1つの全体にして、リスト全体を一度に取り込むことはありません。

+2

Clojureでの適用は、に。 (apply(fn [&args](take args)))(range))は、例えばうまく動作します。 – mikera

9

(reduce op ...)は例外であり(strとconcatの場合を除き)、例外ではありません。

6

私は悪魔の主張をして、applyと主張します。

reduceは(より正確にfoldl)、左倍fold上のClojureのテイクで、折り目の操作は2つの部分があるため、通常は、最初の要素で定義されている: "

  • 初期(またはをゼロ」)値

  • 動作との和を見つけるために、二つの値

    よう

を合成します数字の+を使用する自然な方法は、(fold + 0 values)、または、クロージャでは、(reduce + 0 values)です。結局、+バイナリ演算子である(すべてのことfoldニーズや想定して) - それは私には明らかにされていませんので、

これは明示的に+戻り、この場合の0があることが重要である空のリスト、の結果を示し。

実際には、クロージャーの+は、となり、2進演算子よりもと定義されています。それは多くの、あるいはゼロの値を取ることになります。クール。この「余分な」情報を使用している場合は、それを読者に知らせるのがやりやすいです。​​これは - 「私は奇妙な方法で+をバイナリ演算子以上に使用しています」と言っています。それは人々(私、少なくとも)がコードを理解するのに役立ちます。

[applyがなぜもっと鮮明に感じるのか興味深いです。 「+は、複数の値を受け入れるように設計されています(これは、どのような適用が適用されるかを示しています)。したがって、言語実装にはゼロの値が含まれます。その暗黙の引数は、reduceが単一のリストに適用されていません。]

または、(reduce + 0 values)も問題ありません。 (reduce + values)が私の本能的な反応を誘発します: "ねえ、+はゼロを返しますか?"

、あなたが同意しない場合は、downvoteや回答を投稿する前に、そして、あなたは(reduce * values)は空のリストのために返されるかについて必ずますしてください?

関連する問題