F# 惯用的 async while 循环累加转换

Posted

技术标签:

【中文标题】F# 惯用的 async while 循环累加转换【英文标题】:F# idiomatic conversion of async while loop accumulation 【发布时间】:2019-08-18 05:12:42 【问题描述】:

处理异步 while 循环累积的惯用 F# 方式是什么?

我正在使用新的(仍为预览版)Azure Cosmos DB SDK。查询数据库返回一个CosmosResultSetIterator<T>,它有一个HasMoreResults 属性和一个FetchNextSetAsync() 方法。我对 C# 代码的直接翻译如下所示:

let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
    let results = ResizeArray<'a>()
    async 
        while resultSetIterator.HasMoreResults do
            let! response = resultSetIterator.FetchNextSetAsync() |> Async.AwaitTask
            results.AddRange(response |> Seq.toArray)

        return Seq.toList results
    

【问题讨论】:

次要:我会移动 let results 到异步块,因为我怀疑这是你想要的? 【参考方案1】:

我会看看AsyncSeq 包。您可以使用它来创建异步计算的序列,然后异步或并行迭代它们。这允许异步绑定在序列内,并且让产量异步发生,因此您不必显式构建累加器。

您可以使用它来执行以下操作:

open FSharp.Control

let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
    asyncSeq 
        while resultSetIterator.HasMoreResults do
            let! response = resultSetIterator.FetchNextSetAsync() |> Async.AwaitTask
            yield! response |> AsyncSeq.ofSeq
    

【讨论】:

这看起来很有趣,谢谢。但是有一个问题,在上面的代码中,响应本身是一个序列,我需要返回每个项目作为响应,所以我认为 yield response 不会起作用。我似乎需要某种嵌套的收益。 @BrianVallelunga 哦,这很容易。您只需将其设为yield!,它将使序列变平。我已经更新了答案。 谢谢!我试过了,效果很好。由于响应与AsyncSeq 不直接兼容,因此我确实必须做一个小改动。我最终将最后一行更改为yield! response |&gt; AsyncSeq.ofSeq【参考方案2】:

恕我直言,尾递归优于 while 循环,因为它是避免突变的一种方法。

例如:

let fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
  let rec loop results =
    async 
      if resultSetIterator.HasMoreResults then
        let! vs = resultSetIterator.FetchNextSetAsync () |> Async.AwaitTask
        let vs = vs |> Seq.toList
        return! loop (vs::results)
      else
        // List.rev needed because batches are in reverse
        return results |> List.rev |> List.concat
    
  loop []

【讨论】:

这是我在没有 AsyncSeq 的情况下采用的方法。

以上是关于F# 惯用的 async while 循环累加转换的主要内容,如果未能解决你的问题,请参考以下文章

while循环语句

条件语句,while循环语句:完整的温度转换程序

条件语句,while循环语句:完整的温度转换程序

051Java中使用while循环实现1~100的累加

带有承诺的while循环

052Java中使用do…while循环实现1~100的累加