Search code examples
asynchronousf#sequential-workflow

sequential execution chaining of async operations in F#


Is there any primitive in the langage to compose async1 then async2, akin to what parallel does for parallel execution planning ?

to further clarify, I have 2 async computations

  let toto1 = Async.Sleep(1000)
  let toto2 = Async.Sleep(1000)

I would like to create a new async computation made of the sequential composition of toto1 and toto2

  let toto = Async.Sequential [|toto1; toto2|]

upon start, toto would run toto1 then toto2, and would end after 2000 time units


Solution

  • The async.Bind operation is the basic primitive that asynchronous workflows provide for sequential composition - in the async block syntax, that corresponds to let!. You can use that to express sequential composition of two computations (as demonstrated by Daniel).

    However, if you have an operation <|> that Daniel defined, than that's not expressive enough to implement async.Bind, because when you compose things sequentially using async.Bind, the second computation may depend on the result of the first one. The <e2> may use v1:

    async.Bind(<e1>, fun v1 -> <e2>)
    

    If you were writing <e1> <|> <e2> then the two operations have to be independent. This is a reason why the libraries are based on Bind - because it is more expressive form of sequential composition than the one you would get if you were following the structure of Async.Parallel.

    If you want something that behaves like Async.Parallel and takes an array, then the easiest option is to implement that imperatively using let! in a loop (but you could use recursion and lists too):

    let Sequential (ops:Async<'T>[]) = async {
      let res = Array.zeroCreate ops.Length
      for i in 0 .. ops.Length - 1 do
        let! value = ops.[i]
        res.[i] <- value 
      return res }