Here's the is_prime:
let is_prime n =
let max = int (sqrt (float n)) in
not ( (2 --> max) |> Range.find (fun d -> n mod d = 0) )
let primes = (1000000 --> 1100000) |> Range.pfilter is_prime
let () = puts (showInt (sum primes))
0.39s using Range.filter, 0.24s using Range.pfilter.
Oh right, added the following parallel functions too:
pfilter, pfoldl1, pfoldrand
pfoldr1. Most of the parallel combinators could be abstracted into
splitInto process_count input |> par_map f |> combine, which is what I'll probably do next.
 Did the refactoring, eliminating 70+ lines, here is the new version:
let par_mapReduce ?process_count ~rf ~mf l =
let process_count = process_count |? !global_process_count in
splitInto process_count l |> par_map ~process_count mf |> rf
let pmapReduce rf mf = par_mapReduce ~rf ~mf
let pfoldl r f init = pmapReduce (foldl1 r) (foldl f init)
let pfoldl1 f = pmapReduce (foldl1 f) (foldl1 f)
let pfoldr r f init = pmapReduce (foldr1 r) (foldr f init)
let pfoldr1 f = pmapReduce (foldr1 f) (foldr1 f)
let piter f = pmapReduce ignore (iter f)
let pmap f = pmapReduce concat (map f)
let pfilter f = pmapReduce concat (filter f)
If you have a collection module with splitInto and some of the other functions, you can basically paste this right in. With Range it wasn't quite that easy because par_map returns a list, so the foldls have to use List.foldl for the reduce fold. And I haven't made foldrs for Range, so couldn't add the pfoldrs.
It feels like a promising start towards generalizing the parallel iterators though.