Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimizing syntax for mapped async sequences in F#

I am trying to figure out efficient syntax for the following F# expression. Let's say I have an F# async computation:

let asyncComp n = async { return n }

It has a signature 'a -> Async<'a>. Now I define a sequence of those:

let seqOfAsyncComps = 
    seq {
        yield asyncComp 1
        yield asyncComp 2
        yield asyncComp 3
    }

Now I have an item of seq<Async<int>>. What if I want to asynchronously map the elements from seq<Async<int>> to seq<Async<int>>. This won't work:

let seqOfAsyncSquares =
    seqOfAsyncComps |> Seq.map (fun x -> x * x) // ERROR!!!

Of course, x is Async<int>, I have to extract an int first, so I can do the following instead:

let seqOfAsyncSquares =
    seqOfAsyncComps |> Seq.map (fun x -> async { 
                                            let! y = x
                                            return y * y }) // OK

This works fine but the syntax is clumsy. It takes away F# compactness, and if I want to chain several seq processing I have to do the same trick in every map, filter or iter.

I suspect there might be a more efficient syntax to deal with sequences that consist of async computations.

like image 497
Vagif Abilov Avatar asked Apr 05 '15 15:04

Vagif Abilov


1 Answers

You could use Async.map (that I've only now blatantly stolen from Tomas Petricek):

module Async =
  let map f workflow = async {
    let! res = workflow
    return f res }

let seqOfAsyncSquares' =
    seqOfAsyncComps |> Seq.map (Async.map (fun x -> x * x))

If you evaluate it, you'll see that it seems to produce the expected outcome:

> seqOfAsyncSquares' |> Async.Parallel |> Async.RunSynchronously;;
val it : int [] = [|1; 4; 9|]
like image 142
Mark Seemann Avatar answered Oct 12 '22 09:10

Mark Seemann