Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In an attempt to learn more about Clojure's parallel computation functions, I devised the following task: calculate a factorial in parallel using pmap, pcalls and pvalues.

The idea is to split the factorial sequence into sub-computations, reducing the final output of each.

Here is the obvious non-parallel function:

(defn factorial [n] (reduce * (range 1 (inc n))

pmap is fairly straight-forward:

(defn pmap-factorial [n psz]
  (let [parts (partition-all psz (range 1 (inc n)))]
    (reduce * (pmap #(apply * %) parts))))

However, with pvalues I had to resort to macros that return a computation function.

(defmacro pvalues-factorial [n psz]
  (let [exprs (for [p (partition-all psz (range 1 (inc n)))]
                 (cons '* p))]
    `(fn [] (reduce * (pvalues ~@exprs)))))

Similar approach with pcalls:

(defmacro pcalls-factorial [n psz]
  (let [exprs (for [p (partition-all psz (range 1 (inc n)))]
                     `(fn [] (* ~@p)))]
    `(fn [] (reduce * (pcalls ~@exprs)))))

So, I had to use macros for pcalls and pvalues. Does not seem ideal, but it was the only way I could accomplish the above (and perhaps indicates that pmaps is the best practice for this use case).


1) How could the code be made more correct / idiomatic?

2) Did I have to resort to macros for pvalues and pcalls, or have I overlooked another way of accomplishing my goal with these functions?

share|improve this question
up vote 1 down vote accepted

1) that is quite idomatic Clojure from what I have seen.

2) macros are "contagious" if the thing you are trying to call is a macro and you want to do anything requiring first-class-functions (map apply reduce etc...) then the thing doing the applying must it's self be a macro.

This is why the coding standards for clojure.contrib stable releases require that your library provide a non-macro way to access it's services in addition to the macro one. as your problem nicely demonstrates. macros are incredibly useful, and they are not first class

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.