Skip to main content

This library brings C#'s concept of 'await foreach' to F#, with a seamless implementation of IAsyncEnumerable<'T>. The 'taskSeq' computation expression adds support for awaitable asynchronous sequences with similar ease of use and performance to F#'s 'task' CE, with minimal overhead through ValueTask under the hood. TaskSeq brings 'seq' and 'task' together in a safe way. Generates optimized IL code through resumable state machines, and comes with a comprehensive set of functions in module 'TaskSeq'. See README for documentation and more info.

Total Downloads
823.9K
823,862
Published
Apr 17, 2026
6mo ago

Get Started

dotnet add package FSharp.Control.TaskSeq --version 1.1.1
ProductVersions
.NET Standard
netstandard2.1

README

TaskSeq

An implementation of IAsyncEnumerable<'T> as a computation expression: taskSeq { ... } with an accompanying TaskSeq module and functions, that allow seamless use of asynchronous sequences similar to F#'s native seq and task CE's.

This readme covers the highlights and a summary of implemented functions. A more extensive overview can be found in the repository's readme.


Table of contents


Overview

The IAsyncEnumerable interface was added to .NET in .NET Core 3.0 and is part of .NET Standard 2.1. The main use-case was for iterative asynchronous, sequential enumeration over some resource. For instance, an event stream or a REST API interface with pagination, asynchronous reading over a list of files and accumulating the results, where each action can be modeled as a MoveNextAsync call on the IAsyncEnumerator<'T> given by a call to GetAsyncEnumerator().

Since the introduction of task in F# the call for a native implementation of task sequences has grown, in particular because proper iterating over an IAsyncEnumerable has proven challenging, especially if one wants to avoid mutable variables. This library is an answer to that call and implements the same resumable state machine approach with taskSeq.

Module functions

As with seq and Seq, this library comes with a bunch of well-known collection functions, like TaskSeq.empty, isEmpty or TaskSeq.map, iter, collect, fold and TaskSeq.find, pick, choose, filter. Where applicable, these come with async variants, like TaskSeq.mapAsync iterAsync, collectAsync, foldAsync and TaskSeq.findAsync, pickAsync, chooseAsync, filterAsync, which allows the applied function to be asynchronous.

See below for a full list of currently implemented functions and their variants.

taskSeq computation expressions

The taskSeq computation expression can be used just like using seq. On top of that, it adds support for working with tasks through let! and looping over a normal or asynchronous sequence (one that implements IAsyncEnumerable<'T>'). You can use yield! and yield and there's support for use and use!, try-with and try-finally and while loops within the task sequence expression.

Examples

open System.IO
open FSharp.Control

// singleton is fine
let helloTs = taskSeq { yield "Hello, World!" }

// cold-started, that is, delay-executed
let f() = task {
    // using toList forces execution of whole sequence
    let! hello = TaskSeq.toList helloTs  // toList returns a Task<'T list>
    return List.head hello
}

// can be mixed with normal sequences
let oneToTen = taskSeq { yield! [1..10] }

// can be used with F#'s task and async in a for-loop
let f() = task { for x in oneToTen do printfn "Number %i" x }
let g() = async { for x in oneToTen do printfn "Number %i" x }

// returns a delayed sequence of IAsyncEnumerable<string>
let allFilesAsLines() = taskSeq {
    let files = Directory.EnumerateFiles(@"c:\temp")
    for file in files do
        // await
        let! contents = File.ReadAllLinesAsync file
        // return all lines
        yield! contents
}

let write file =
    allFilesAsLines()

    // synchronous map function on asynchronous task sequence
    |> TaskSeq.map (fun x -> x.Replace("a", "b"))

    // asynchronous map
    |> TaskSeq.mapAsync (fun x -> task { return "hello: " + x })

    // asynchronous iter
    |> TaskSeq.iterAsync (fun data -> File.WriteAllTextAsync(fileName, data))


// infinite sequence
let feedFromTwitter user pwd = taskSeq {
    do! loginToTwitterAsync(user, pwd)
    while true do
       let! message = getNextNextTwitterMessageAsync()
       yield message
}

TaskSeq module functions

We are working hard on getting a full set of module functions on TaskSeq that can be used with IAsyncEnumerable sequences. Our guide is the set of F# Seq functions in F# Core and, where applicable, the functions provided by AsyncSeq. Each implemented function is documented through XML doc comments to provide the necessary context-sensitive help.

This is what has been implemented so far, is planned or skipped:

Done Seq TaskSeq Variants Remarks
❓ allPairs allPairs note #1
βœ… #81 append append
βœ… #81 appendSeq
βœ… #81 prependSeq
average average
averageBy averageBy averageByAsync
❓ cache cache note #1
βœ… #67 cast cast
βœ… #67 box
βœ… #67 unbox
βœ… #23 choose choose chooseAsync
chunkBySize chunkBySize
βœ… #11 collect collect collectAsync
βœ… #11 collectSeq collectSeqAsync
compareWith compareWith compareWithAsync
βœ… #69 concat concat
βœ… #237 concat (list) concat (list)
βœ… #237 concat (array) concat (array)
βœ… #237 concat (r-array) concat (r-array)
βœ… #237 concat (seq) concat (seq)
βœ… #70 contains contains
βœ… #82 delay delay
distinct distinct
distinctBy dictinctBy distinctByAsync
βœ… #209 drop
βœ… #2 empty empty
βœ… #23 exactlyOne exactlyOne
βœ… #83 except except
βœ… #83 exceptOfSeq
βœ… #70 exists exists existsAsync
exists2 exists2
βœ… #23 filter filter filterAsync
βœ… #23 find find findAsync
🚫 findBack note #2
βœ… #68 findIndex findIndex findIndexAsync
🚫 findIndexBack n/a n/a note #2
βœ… #2 fold fold foldAsync
fold2 fold2 fold2Async
🚫 foldBack note #2
🚫 foldBack2 note #2
βœ… #240 forall forall forallAsync
forall2 forall2 forall2Async
❓ groupBy groupBy groupByAsync note #1
βœ… #23 head head
βœ… #68 indexed indexed
βœ… #69 init init initAsync
βœ… #69 initInfinite initInfinite initInfiniteAsync
βœ… #236 insertAt insertAt
βœ… #236 insertManyAt insertManyAt
βœ… #23 isEmpty isEmpty
βœ… #23 item item
βœ… #2 iter iter iterAsync
iter2 iter2 iter2Async
βœ… #2 iteri iteri iteriAsync
iteri2 iteri2 iteri2Async
βœ… #23 last last
βœ… #53 length length
βœ… #53 lengthBy lengthByAsync
βœ… #2 map map mapAsync
map2 map2 map2Async
map3 map3 map3Async
mapFold mapFold mapFoldAsync
🚫 mapFoldBack note #2
βœ… #2 mapi mapi mapiAsync
mapi2 mapi2 mapi2Async
βœ… #221 max max
βœ… #221 maxBy maxBy maxByAsync
βœ… #221 min min
βœ… #221 minBy minBy minByAsync
βœ… #2 ofArray ofArray
βœ… #2 ofAsyncArray
βœ… #2 ofAsyncList
βœ… #2 ofAsyncSeq
βœ… #2 ofList ofList
βœ… #2 ofTaskList
βœ… #2 ofResizeArray
βœ… #2 ofSeq
βœ… #2 ofTaskArray
βœ… #2 ofTaskList
βœ… #2 ofTaskSeq
pairwise pairwise
permute permute permuteAsync
βœ… #23 pick pick pickAsync
🚫 readOnly note #3
reduce reduce reduceAsync
🚫 reduceBack note #2
βœ… #236 removeAt removeAt
βœ… #236 removeManyAt removeManyAt
replicate replicate
❓ rev note #1
scan scan scanAsync
🚫 scanBack note #2
βœ… #90 singleton singleton
βœ… #209 skip skip
βœ… #219 skipWhile skipWhile skipWhileAsync
βœ… #219 skipWhileInclusive skipWhileInclusiveAsync
❓ sort note #1
❓ sortBy note #1
❓ sortByAscending note #1
❓ sortByDescending note #1
❓ sortWith note #1
splitInto splitInto
sum sum
sumBy sumBy sumByAsync
βœ… #76 tail tail
βœ… #209 take take
βœ… #126 takeWhile takeWhile takeWhileAsync
βœ… #126 takeWhileInclusive takeWhileInclusiveAsync
βœ… #2 toArray toArray toArrayAsync
βœ… #2 toIList toIListAsync
βœ… #2 toList toList toListAsync
βœ… #2 toResizeArray toResizeArrayAsync
βœ… #2 toSeq toSeqAsync
[…]
❓ transpose note #1
βœ… #209 truncate truncate
βœ… #23 tryExactlyOne tryExactlyOne tryExactlyOneAsync
βœ… #23 tryFind tryFind tryFindAsync
🚫 tryFindBack note #2
βœ… #68 tryFindIndex tryFindIndex tryFindIndexAsync
🚫 tryFindIndexBack note #2
βœ… #23 tryHead tryHead
βœ… #23 tryItem tryItem
βœ… #23 tryLast tryLast
βœ… #23 tryPick tryPick tryPickAsync
βœ… #76 tryTail
unfold unfold unfoldAsync
βœ… #236 updateAt updateAt
βœ… #217 where where whereAsync
windowed windowed
βœ… #2 zip zip
zip3 zip3
zip4
Note 1

These functions require a form of pre-materializing through TaskSeq.cache, similar to the approach taken in the corresponding Seq functions. It doesn't make much sense to have a cached async sequence. However, AsyncSeq does implement these, so we'll probably do so eventually as well.

Note 2

Because of the async nature of TaskSeq sequences, iterating from the back would be bad practice. Instead, materialize the sequence to a list or array and then apply the xxxBack iterators.

Note 3

The motivation for readOnly in Seq is that a cast from a mutable array or list to a seq<_> is valid and can be cast back, leading to a mutable sequence. Since TaskSeq doesn't implement IEnumerable<_>, such casts are not possible.

More information

Further reading IAsyncEnumerable

  • A good C#-based introduction can be found in this blog.
  • An MSDN article written shortly after it was introduced.
  • Converting a seq to an IAsyncEnumerable demo gist as an example, though TaskSeq contains many more utility functions and uses a slightly different approach.
  • If you're looking for using IAsyncEnumerable with async and not task, the excellent AsyncSeq library should be used. While TaskSeq is intended to consume async just like task does, it won't create an AsyncSeq type (at least not yet). If you want classic Async and parallelism, you should get this library instead.

Further reading on resumable state machines

Further reading on computation expressions

Downloads by Version

Similar & Alternative Packages

Hand-picked matching NuGet libraries based on tags & ecosystem

Depended On By

Find packages that declare this package as a dependency. NuGet does not provide a reverse-dependency endpoint, so candidates are checked on demand.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 1 target framework; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.