Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rewriting C# code using Task.WhenAll in F#

I have the following interface method:

Task<string[]> GetBlobsFromContainer(string containerName);

and its implementation in C#:

var container = await _containerClient.GetContainer(containerName);
var tasks = container.ListBlobs()
                     .Cast<CloudBlockBlob>()
                     .Select(b => b.DownloadTextAsync());
return await Task.WhenAll(tasks);

When I try to rewrite it in F#:

member this.GetBlobsFromContainer(containerName : string) : Task<string[]> =
    let task = async {
        let! container = containerClient.GetContainer(containerName) |> Async.AwaitTask
        return container.ListBlobs()
               |> Seq.cast<CloudBlockBlob>
               |> Seq.map (fun b -> b.DownloadTextAsync())
               |> ??
    }
    task |> ??

I'm stuck with the last lines.

How to return to Task<string[]> from F# properly?

like image 266
abatishchev Avatar asked Aug 09 '15 05:08

abatishchev


2 Answers

I had to guess what the type of containerClient is and the closest I found is CloudBlobClient (which does not have getContainer: string -> Task<CloubBlobContainer> but it shouldn't be too hard to adapt). Then, your function might look like as follows:

open System
open System.Threading.Tasks
open Microsoft.WindowsAzure.Storage.Blob
open Microsoft.WindowsAzure.Storage

let containerClient : CloudBlobClient = null

let GetBlobsFromContainer(containerName : string) : Task<string[]> =
    async {
        let container = containerClient.GetContainerReference(containerName)
        return! container.ListBlobs()
               |> Seq.cast<CloudBlockBlob>
               |> Seq.map (fun b -> b.DownloadTextAsync() |> Async.AwaitTask)
               |> Async.Parallel
    } |> Async.StartAsTask

I changed the return type to be Task<string[]> instead of Task<string seq> as I suppose you want to keep the interface. Otherwise, I'd suggest to get rid of the Task and use Async in F#-only code.

like image 195
CaringDev Avatar answered Nov 14 '22 20:11

CaringDev


Will this work?

member this.GetBlobsFromContainer(containerName : string) : Task<string seq> =
    let aMap f x = async {
        let! a = x
        return f a }
    let task = async {
        let! container = containerClient.GetContainer(containerName) |> Async.AwaitTask
        return! container.ListBlobs()
            |> Seq.cast<CloudBlockBlob>
            |> Seq.map (fun b -> b.DownloadTextAsync() |> Async.AwaitTask)
            |> Async.Parallel
            |> aMap Array.toSeq
    }
    task |> Async.StartAsTask

I had to make some assumptions about containerClient etc. so I haven't been able to test this, but at least it compiles.

like image 37
Mark Seemann Avatar answered Nov 14 '22 21:11

Mark Seemann