0
\$\begingroup\$

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).

Questions:

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?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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