title: Flattening nested async sequences in F#
body: <p>Consider a series of F# sequences:</p>
  
  <pre><code>let seqOf123 = seq { for i in 1..3 do yield i }
  let seqOf456 = seq { for i in 4..6 do yield i }
  let seqOf789 = seq { for i in 7..9 do yield i }
  </code></pre>
  
  <p>... and a sequence which contains all of them:</p>
  
  <pre><code>let seqOfSeqOfNums = 
      seq {
          yield seqOf123
          yield seqOf456
          yield seqOf789
      }
  </code></pre>
  
  <p>Now we have a sequence of sequences that we can flatten using built-in Seq.concat function and wrap in async clause to execute asynchronously:</p>
  
  <pre><code>let firstAsyncSeqOfNums = async { return Seq.concat seqOfSeqOfNums }
  </code></pre>
  
  <p>We have a resulting async sequence of 9 numbers with a signature <code>Async&lt;seq&lt;int&gt;&gt;</code>that we will come back to.</p>
  
  <p>Now consider a series of async sequences:</p>
  
  <pre><code>let asyncSeqOf123 = async { return seqOf123 }
  let asyncSeqOf456 = async { return seqOf456 }
  let asyncSeqOf789 = async { return seqOf789 }
  </code></pre>
  
  <p>... and a sequence containing them:</p>
  
  <pre><code>let seqOfAsyncSeqOfNums = 
      seq {
          yield asyncSeqOf123
          yield asyncSeqOf456
          yield asyncSeqOf789
      }
  </code></pre>
  
  <p>We have now a sequence of type <code>seq&lt;Async&lt;seq&lt;int&gt;&gt;&gt;</code>. We can't flatten this one using Seq.concat because it's a sequence of async sequences. So how can we convert it to a type <code>Async&lt;seq&lt;int&gt;&gt;</code> where all integer data are flattened? We can try to do the following:</p>
  
  <pre><code>let secondAsyncSeqOfNums = 
      async {
          return seqOfAsyncSeqOfNums
          |&gt; Seq.map (fun x -&gt; x |&gt; Async.RunSynchronously)
          |&gt; Seq.concat
      }
  </code></pre>
  
  <p>It looks like it does its job: it has a type <code>Async&lt;seq&lt;int&gt;&gt;</code> and if we pipe it to Async.RunSynchronously it will produce the same sequence of 9 integers. But the way it produces the same sequence is not equivalent to firstAsyncSeqOfNums that appears above. The implementation of secondAsyncSeqOfNums calls Async.RunSynchronously for every nested sequence of integers during the generation of a singe flattened sequence. But can this be avoided? Note that we are generating an async flattened sequence that ideally would need only a single call to Async.RunSynchronously to evaluate its content. But I can't find a way to rewrite the code without Async.RunSynchronously being called multiple times.</p>