guerrillacodester
guerrillacodester

Reputation: 531

How to convert a Parallel.Foreach in C# to F#?

I have been trying to convert some C# to F# and it hasn't been going so good as I am relatively new to F#

Here is the working C# snippet:

static void doParallelForeach()
{
    // The sum of these elements is 40.
    int[] input = { 4, 1, 6, 2, 9, 5, 10, 3 };
    int sum = 0;

    Parallel.ForEach(
        input, 
        () => 0,   
        (n, loopState, localSum) => 
        {
            localSum += n;
            Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum);
            return localSum;
        },
        (localSum) => Interlocked.Add(ref sum, localSum)
    );
}

Here is the F# snippet that gives this compiler error: No overloads match for method 'ForEach'.

let doParallelForeach =

let input:int[] = [|4; 1; 6; 2; 9; 5; 10; 3|]

let sum = 0

Parallel.ForEach

(
    input,

    (fun ()-> 0),

    (fun (n, loopState, localSum) ->
        localSum += n
        Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum);
        return localSum),

    (fun (localSum) -> Interlocked.Add(ref sum, localSum))

)

Can someone please explain what I am doing wrong?

Upvotes: 1

Views: 1323

Answers (1)

kvb
kvb

Reputation: 55195

There are lots of problems with your code. Here's a literal translation:

let doParallelForeach() =
    let input:int[] = [|4; 1; 6; 2; 9; 5; 10; 3|]
    let sum = ref 0

    Parallel.ForEach (
            input,
            (fun ()-> 0),
            (fun n loopState localSum->
                let localSum = localSum + n
                Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum)
                localSum),
            (fun (localSum) -> Interlocked.Add(sum, localSum) |> ignore))

Notes:

  1. Since your C# code uses a method, I've made doParallelForeach into a function instead of a value of type unit.
  2. return and += aren't valid F# code. You don't need to use return in F#, and you can only modify mutable values (and even then, there are no compound assignment operators). Instead, we just shadow localSum with a new value.
  3. You're using ref incorrectly - it is a function in F#, not a modifier, and it is used to define new reference values, not to extract addresses to pass to methods. Furthermore, since sum was a let-bound immutable value, you couldn't take its address anyway. The correct way to do this is to use F#'s ref function to make sum an instance of the int ref type.
  4. In F#, you use curried (as opposed to tupled) function definitions when defining a delegate. That is, you use fun n loopState localSum -> ... instead of fun (n, loopState, localSum) -> ....

Note that regardless of these fixes, this is a weird method - the results are kept in a local variable (sum) which isn't ever exposed to the caller...

Upvotes: 7

Related Questions