F#中的Async类型不匹配

时间:2010-02-26 17:25:38

标签: f#

我刚刚开始搞乱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返回类型?

1 个答案:

答案 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