1

我一直在尝试将一些 C# 转换为 F#,但效果并不好,因为我对 F# 还比较陌生

这是有效的 C# 片段:

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)
    );
}

这是给出此编译器错误的 F# 片段:没有重载匹配方法“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))

)

有人可以解释我做错了什么吗?

4

1 回答 1

7

你的代码有很多问题。这是一个字面翻译:

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

笔记:

  1. 由于您的 C# 代码使用方法,因此我将其制成doParallelForeach函数而不是 type 的值unit
  2. return并且+=不是有效的 F# 代码。你不需要return在 F# 中使用,你只能修改可变值(即使那样,也没有复合赋值运算符)。相反,我们只是localSum用一个新的值来遮蔽。
  3. 您使用ref不正确 - 它是 F# 中的函数,而不是修饰符,它用于定义新的引用值,而不是提取地址以传递给方法。此外,由于sum它是一个 let 绑定的不可变值,因此无论如何您都无法获取它的地址。正确的方法是使用 F# 的ref函数来创建该类型sum的实例。int ref
  4. 在 F# 中,您在定义委托时使用 curried(而不是 tupled)函数定义。也就是说,您使用fun n loopState localSum -> ...而不是fun (n, loopState, localSum) -> ....

请注意,无论这些修复如何,这是一个奇怪的方法 - 结果保存在一个局部变量 ( sum) 中,该变量从未暴露给调用者...

于 2013-04-29T20:41:46.813 回答