views:

496

answers:

4

Should I use

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

or

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

Edit: This is the source for prime in clojure from optimizing toolkit.

(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)))))))
+11  A: 

If you are asking in terms of performance, the reduce is better by a little:

(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

About 7% difference in this case, but YMMV depending on the machine.

You haven't provided your source for the prime? function, so I have substituted even? as the predicate. Keep in mind that your runtime may be dominated by prime?, in which case the choice between reduce and apply matters even less.

If you are asking which is more "lispy" then I would say that the reduce implementation is preferrable, as what you are doing is a reduce/fold in the functional programming sense.

alanlcode
+7  A: 

I would think that reduce would be preferable when it is available, because apply uses the list as arguments to the function, but when you have a large number -- say, a million -- elements in the list, you will construct a function call with a million arguments! That might cause some problems with some implementations of Lisp.

newacct
Common Lisp has a constant CALL-ARGUMENTS-LIMIT.
Rainer Joswig
+7  A: 

I would expect apply to realize a lazy list which could be ugly, and you never want to assume your list is not lazy, 'cause you could suddenly find yourself getting smacked with massive memory useage.

Reduce is going to grab them 1 by one and roll the results together into a single whole, never taking the whole list in at once.

Runevault
+7  A: 

(reduce op ...) is the norm and (apply op ...) the exception (notably for str and concat).

cgrand