我刚刚开始搞乱F#,我正在尝试做一些基本的并行计算以熟悉语言。我遇到了类型不匹配的问题。这是一个例子:
let allVariances list =
seq {
for combination in allCombinations list do
yield (combination, abs(targetSum - List.sum combination))
}
let compareVariance tup1 tup2 =
if snd tup1 < snd tup2 then
tup1
else
tup2
let aCompareVariance tup1 tup2 =
async { return compareVariance tup1 tup2 }
let matchSum elements targetSum =
allVariances elements
|> Seq.reduce aCompareVariance
|> Async.Parallel
|> Async.RunSynchronously
因此,“allVariances元素”会生成seq <float list * float
&gt;。 CompareVariance需要其中两个<float list * float
&gt;元组并返回具有较小的第二项(方差)的元组。我的目标是使用Reduce以最小的方差结束元组。但是,我在aCompareVariance参数上遇到类型不匹配:
错误1类型不匹配。期待浮动列表*浮动 - &gt;浮动列表*浮点数 - &gt; float list * float但是给出了一个浮点列表* float - &gt;浮动列表*浮点数 - &gt;异步<float list * float
&GT;类型'float list * float'与'Async <float list * float
&gt;'
似乎Reduce不接受Async返回类型?
答案 0 :(得分:2)
Seq.reduce
接受一个函数和一个序列,并使用该函数减少列表。也就是说,使用函数{a1;a2;a3;...;an}
减少序列f
的结果将是f(f(...f(f(a1,a2),a3),...),an))...)
。但是,您传递的函数不能以这种方式应用,因为返回类型(Async<float list * float>
)与参数类型(float list * float
)不匹配。你究竟想要实现什么目标?
另外,请记住,async
计算对于异步工作非常有用,但对于并行工作并不理想。请参阅F#: Asynch and Tasks and PLINQ, oh my!和Task Parallel Library vs Async Workflows。
修改强>
这是一种编写函数的方法,它可以减少项目,就像你期望的那样,操作类似:
[|a1; a2; a3; a4|]
[|f a1 a2; f a3 a4|]
f (f a1 a2) (f a3 a4)
在每个阶段,f的所有应用程序将并行进行。这使用Async.Parallel
,如上所述,它可能不如使用任务并行库(甚至可能比正常的同步Array.reduce
慢)。因此,只需将此视为演示代码,演示如何拼凑异步函数。
let rec reduce f (arr:_[]) =
match arr.Length with
| 0 -> failwith "Can't reduce an empty array"
| 1 -> arr.[0]
| n ->
// Create an array with n/2 tasks, each of which combines neighboring entries using f
Array.init ((n+1)/2)
(fun i ->
async {
// if n is odd, leave last item alone
if n = 2*i + 1 then
return arr.[2*i]
else
return f arr.[2*i] arr.[2*i+1]})
|> Async.Parallel |> Async.RunSynchronously
|> reduce f
请注意,在Async
值之间转换项目都发生在此函数内部,因此它与Array.reduce
具有相同的类型,并且将与您的普通compareVariance
函数一起使用,而不是与aCompareVariance
。