我一直在尝试将一些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))
)
有人可以解释一下我做错了吗?
答案 0 :(得分: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))
注意:
doParallelForeach
变为函数而不是unit
类型的值。return
和+=
不是有效的F#代码。您不需要在F#中使用return
,并且您只能修改可变值(即使这样,也没有复合赋值运算符)。相反,我们只是用新值隐藏localSum
。ref
- 它是F#中的函数,而不是修饰符,它用于定义新的引用值,而不是提取要传递给方法的地址。此外,由于sum
是一个let-bound不可变值,因此无论如何都无法获取其地址。正确的方法是使用F#的ref
函数使sum
成为int ref
类型的实例。fun n loopState localSum -> ...
代替fun (n, loopState, localSum) -> ...
。请注意,无论这些修复程序如何,这都是一种奇怪的方法 - 结果保存在一个局部变量(sum
)中,该变量不会暴露给调用者......