Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# idiomatic conversion of async while loop accumulation

What is the idiomatic F# way of handling an asynchronous while loop accumulation?

I'm working with the new (still in preview) Azure Cosmos DB SDK. Querying the database returns a CosmosResultSetIterator<T> which has a HasMoreResults property and a FetchNextSetAsync() method. My straight-up translation of the C# code looks like this:

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
    }
like image 229
Brian Vallelunga Avatar asked Mar 27 '19 15:03

Brian Vallelunga


1 Answers

I would take a look at the AsyncSeq package. You can use it to create asynchronously computed sequences and then iterate them asynchronously or in parallel. This allows for the async-binding to be inside the sequence and the yield to occur asynchronously, so you don't have to build up an accumulator explicitly.

You can use it to do something like:

open FSharp.Control

let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
    asyncSeq {
        while resultSetIterator.HasMoreResults do
            let! response = resultSetIterator.FetchNextSetAsync() |> Async.AwaitTask
            yield! response |> AsyncSeq.ofSeq
    }
like image 158
Aaron M. Eshbach Avatar answered Sep 19 '22 05:09

Aaron M. Eshbach