3.6. Parallelism across languages
Because implementations are interchangeable, so are execution strategies. Here
is a parallel map written in Python, driving a summation written in C++:
foo.hpp
#pragma once
#include <vector>
double sum(const std::vector<double>& vec) {
double sum = 0.0;
for (double value : vec) {
sum += value;
}
return sum;
}
foo.py
import multiprocessing as mp
def pmap(f, xs):
with mp.Pool() as pool:
results = pool.map(f, xs)
return results
sums.loc
module sums (sumOfSums)
import root-py
import root-cpp
source Py from "foo.py" ("pmap")
source Cpp from "foo.hpp" ("sum")
pmap :: (a -> b) -> [a] -> [b]
sum :: [Real] -> Real
sumOfSums = sum . pmap sum
sumOfSums sums a list of lists. The . operator is function composition, so
this reads right to left: pmap sum sums each inner list in parallel, and the
outer sum adds the results.
The lowercase a and b in pmap’s signature are type variables, meaning
`pmap works for any element types. That signature is the ordinary map’s,
fixed to lists, so the two are interchangeable here: writing `map sum instead
of pmap sum compiles and gives the same answer. Parallelism is a choice of
implementation, not a change to the program.
$ morloc make sums.loc
$ ./sums sumOfSums '[[1,2],[3,4,5]]'
15