Consuming Task Sequences
All TaskSeq<'T> values are lazy — they produce elements only when actively consumed. This
page covers all the ways to consume a task sequence: iteration with side effects, collection
into arrays and lists, folding, aggregation, searching, and element access.
open System.Threading.Tasks
open FSharp.Control
let numbers : TaskSeq<int> = TaskSeq.ofSeq (seq { 1..5 })
Iterating with a for loop
Inside a task { ... } or taskSeq { ... } computation expression, you can iterate a
TaskSeq<'T> with a plain for loop. The loop body may contain let! and do!:
task {
for n in numbers do
printfn "Got %d" n
}
|> Task.WaitAll
iter and iterAsync
TaskSeq.iter applies a synchronous side-effecting function to every element:
let printAll : Task<unit> = numbers |> TaskSeq.iter (printfn "item: %d")
TaskSeq.iterAsync awaits the returned task before consuming the next element — ideal for
actions that themselves do IO, such as writing to a database:
let processItem (n: int) : Task<unit> =
task { printfn "processing %d" n }
let processAll : Task<unit> = numbers |> TaskSeq.iterAsync processItem
iteri and iteriAsync
TaskSeq.iteri and TaskSeq.iteriAsync additionally pass the zero-based index to the action:
let printWithIndex : Task<unit> =
numbers |> TaskSeq.iteri (fun i n -> printfn "[%d] %d" i n)
Collecting into arrays and lists
TaskSeq.toArrayAsync and TaskSeq.toListAsync consume the whole sequence into an in-memory
collection. The blocking (synchronous) variants toArray, toList, and toSeq are also
available when you need them in a synchronous context:
let arr : Task<int[]> = numbers |> TaskSeq.toArrayAsync
let lst : Task<int list> = numbers |> TaskSeq.toListAsync
let rz : Task<System.Collections.Generic.List<int>> = numbers |> TaskSeq.toResizeArrayAsync
// Blocking variants (avoid in async code)
let arrSync : int[] = numbers |> TaskSeq.toArray
let lstSync : int list = numbers |> TaskSeq.toList
fold and foldAsync
TaskSeq.fold threads an accumulator through the sequence, returning the final state:
let sum : Task<int> =
numbers |> TaskSeq.fold (fun acc n -> acc + n) 0
let concat : Task<string> =
TaskSeq.ofList [ "hello"; " "; "world" ]
|> TaskSeq.fold (fun acc s -> acc + s) ""
TaskSeq.foldAsync is the same but the folder returns Task<'State>:
let sumAsync : Task<int> =
numbers
|> TaskSeq.foldAsync (fun acc n -> task { return acc + n }) 0
scan and scanAsync
TaskSeq.scan is like fold but emits each intermediate state as a new element. The output
sequence has N + 1 elements when the input has N, because the initial state is also
emitted:
let runningTotals : TaskSeq<int> =
numbers |> TaskSeq.scan (fun acc n -> acc + n) 0
// yields 0, 1, 3, 6, 10, 15
reduce and reduceAsync
TaskSeq.reduce uses the first element as the initial state — there is no extra zero argument:
let product : Task<int> = numbers |> TaskSeq.reduce (fun acc n -> acc * n)
Aggregation: sum, average, min, max
Numeric aggregates follow the same pattern as the Seq module:
let total : Task<int> = numbers |> TaskSeq.sum
let avg : Task<float> =
TaskSeq.ofList [ 1.0; 2.0; 3.0 ] |> TaskSeq.average
let biggest : Task<int> = numbers |> TaskSeq.max
let smallest : Task<int> = numbers |> TaskSeq.min
sumBy, averageBy, maxBy, and minBy apply a projection first. Async variants
sumByAsync, averageByAsync, maxByAsync, and minByAsync are also available:
let sumOfSquares : Task<int> = numbers |> TaskSeq.sumBy (fun n -> n * n)
length and isEmpty
TaskSeq.length consumes the whole sequence. Use TaskSeq.lengthOrMax to avoid evaluating
more than a known upper bound — useful for infinite sequences or for early termination:
let len : Task<int> = numbers |> TaskSeq.length // 5
let atMost3 : Task<int> = numbers |> TaskSeq.lengthOrMax 3 // 3 (stops early)
let empty : Task<bool> = numbers |> TaskSeq.isEmpty // false
TaskSeq.lengthBy counts elements satisfying a predicate in a single pass:
let countEvens : Task<int> = numbers |> TaskSeq.lengthBy (fun n -> n % 2 = 0)
Element access: head, last, item, exactlyOne
let first : Task<int> = numbers |> TaskSeq.head // 1
let last : Task<int> = numbers |> TaskSeq.last // 5
let third : Task<int> = numbers |> TaskSeq.item 2 // 3 (zero-based)
let only : Task<int> = TaskSeq.singleton 42 |> TaskSeq.exactlyOne // 42
// Safe "try" variants return None instead of throwing:
let tryFirst : Task<int option> = numbers |> TaskSeq.tryHead
let tryLast : Task<int option> = numbers |> TaskSeq.tryLast
let tryThird : Task<int option> = numbers |> TaskSeq.tryItem 2
let tryOnly : Task<int option> = TaskSeq.singleton 42 |> TaskSeq.tryExactlyOne
Searching: find, pick, contains, exists, forall
TaskSeq.find returns the first element satisfying a predicate, or throws if none is found.
TaskSeq.tryFind returns None instead of throwing:
let firstEven : Task<int> = numbers |> TaskSeq.find (fun n -> n % 2 = 0)
let maybeEven : Task<int option> = numbers |> TaskSeq.tryFind (fun n -> n % 2 = 0)
TaskSeq.findIndex and TaskSeq.tryFindIndex return the zero-based index:
let indexOfFirst3 : Task<int> = numbers |> TaskSeq.findIndex (fun n -> n = 3)
TaskSeq.pick and TaskSeq.tryPick are like find but the predicate also projects to a new
value — equivalent to a combined choose + head:
let firstSquareOver10 : Task<int option> =
numbers
|> TaskSeq.tryPick (fun n ->
let sq = n * n
if sq > 10 then Some sq else None)
TaskSeq.contains tests membership by equality. TaskSeq.exists tests with a predicate.
TaskSeq.forall tests that all elements satisfy a predicate:
let has3 : Task<bool> = numbers |> TaskSeq.contains 3
let anyNegative : Task<bool> = numbers |> TaskSeq.exists (fun n -> n < 0)
let allPositive : Task<bool> = numbers |> TaskSeq.forall (fun n -> n > 0)
All search/predicate operations have Async variants (findAsync, existsAsync,
forallAsync, etc.) that accept a predicate returning Task<bool>.
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Control
--------------------
namespace Microsoft.FSharp.Control
module TaskSeq from FSharp.Control.TaskSeqExtensions
--------------------
type TaskSeq = static member append: source1: TaskSeq<'T> -> source2: TaskSeq<'T> -> TaskSeq<'T> static member appendSeq: source1: TaskSeq<'T> -> source2: 'T seq -> TaskSeq<'T> static member box: source: TaskSeq<'T> -> TaskSeq<obj> static member cast: source: TaskSeq<obj> -> TaskSeq<'U> static member choose: chooser: ('T -> 'U option) -> source: TaskSeq<'T> -> TaskSeq<'U> static member chooseAsync: chooser: ('T -> #Task<'U option>) -> source: TaskSeq<'T> -> TaskSeq<'U> static member chunkBySize: chunkSize: int -> source: TaskSeq<'T> -> TaskSeq<'T array> static member collect: binder: ('T -> #TaskSeq<'U>) -> source: TaskSeq<'T> -> TaskSeq<'U> static member collectAsync: binder: ('T -> #Task<'TSeqU>) -> source: TaskSeq<'T> -> TaskSeq<'U> (requires 'TSeqU :> TaskSeq<'U>) static member collectSeq: binder: ('T -> #('U seq)) -> source: TaskSeq<'T> -> TaskSeq<'U> ...
--------------------
type TaskSeq<'T> = System.Collections.Generic.IAsyncEnumerable<'T>
<summary> Represents a task sequence and is the output of using the <paramref name="taskSeq{...}" /> computation expression from this library. It is an alias for <see cref="T:System.IAsyncEnumerable<_>" />. </summary>
--------------------
type TaskSeq<'Machine,'T (requires 'Machine :> IAsyncStateMachine and 'Machine :> IResumableStateMachine<TaskSeqStateMachineData<'T>>)> = inherit TaskSeqBase<'T> interface IValueTaskSource interface IValueTaskSource<bool> interface IAsyncStateMachine interface IAsyncEnumerable<'T> interface IAsyncEnumerator<'T> new: unit -> TaskSeq<'Machine,'T> member InitMachineData: ct: CancellationToken * machine: byref<'Machine> -> unit override MoveNextAsyncResult: unit -> ValueTask<bool>
<summary> Main implementation of generic <see cref="T:System.IAsyncEnumerable<'T>" /> and related interfaces, which forms the meat of the logic behind <see cref="taskSeq" /> computation expresssions. For use by this library only, should not be used directly in user code. Its operation depends highly on resumable state. </summary>
--------------------
new: unit -> TaskSeq<'Machine,'T>
val int: value: 'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val seq: sequence: 'T seq -> 'T seq
--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
type Task = interface IAsyncResult interface IDisposable new: action: Action -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable + 1 overload member ContinueWith: continuationAction: Action<Task,obj> * state: obj -> Task + 19 overloads member Dispose: unit -> unit member GetAwaiter: unit -> TaskAwaiter member RunSynchronously: unit -> unit + 1 overload member Start: unit -> unit + 1 overload member Wait: unit -> unit + 5 overloads ...
<summary>Represents an asynchronous operation.</summary>
--------------------
type Task<'TResult> = inherit Task new: ``function`` : Func<obj,'TResult> * state: obj -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable<'TResult> + 1 overload member ContinueWith: continuationAction: Action<Task<'TResult>,obj> * state: obj -> Task + 19 overloads member GetAwaiter: unit -> TaskAwaiter<'TResult> member WaitAsync: cancellationToken: CancellationToken -> Task<'TResult> + 4 overloads member Result: 'TResult static member Factory: TaskFactory<'TResult>
<summary>Represents an asynchronous operation that can return a value.</summary>
<typeparam name="TResult">The type of the result produced by this <see cref="T:System.Threading.Tasks.Task`1" />.</typeparam>
--------------------
Task(action: System.Action) : Task
Task(action: System.Action, cancellationToken: System.Threading.CancellationToken) : Task
Task(action: System.Action, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj) : Task
Task(action: System.Action, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: System.Threading.CancellationToken) : Task
Task(action: System.Action<obj>, state: obj, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task
--------------------
Task(``function`` : System.Func<'TResult>) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, cancellationToken: System.Threading.CancellationToken) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, cancellationToken: System.Threading.CancellationToken) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, cancellationToken: System.Threading.CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task.WaitAll(tasks: System.ReadOnlySpan<Task>) : unit
Task.WaitAll(tasks: Task array, timeout: System.TimeSpan) : bool
Task.WaitAll(tasks: Task array, cancellationToken: System.Threading.CancellationToken) : unit
Task.WaitAll(tasks: Task array, millisecondsTimeout: int) : bool
Task.WaitAll(tasks: System.Collections.Generic.IEnumerable<Task>, ?cancellationToken: System.Threading.CancellationToken) : unit
Task.WaitAll(tasks: Task array, millisecondsTimeout: int, cancellationToken: System.Threading.CancellationToken) : bool
type List<'T> = interface ICollection<'T> interface IEnumerable<'T> interface IEnumerable interface IList<'T> interface IReadOnlyCollection<'T> interface IReadOnlyList<'T> interface ICollection interface IList new: unit -> unit + 2 overloads member Add: item: 'T -> unit ...
<summary>Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists.</summary>
<typeparam name="T">The type of elements in the list.</typeparam>
--------------------
System.Collections.Generic.List() : System.Collections.Generic.List<'T>
System.Collections.Generic.List(collection: System.Collections.Generic.IEnumerable<'T>) : System.Collections.Generic.List<'T>
System.Collections.Generic.List(capacity: int) : System.Collections.Generic.List<'T>
val string: value: 'T -> string
--------------------
type string = System.String
<summary> Returns the sum of all elements of the task sequence. The elements must support the <c>+</c> operator, which is the case for all built-in numeric types. For sequences with a projection, use <see cref="TaskSeq.sumBy" />. </summary>
<param name="source">The input task sequence.</param>
<returns>The sum of all elements in the sequence, starting from <c>Unchecked.defaultof</c> as zero.</returns>
<exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
val float: value: 'T -> float (requires member op_Explicit)
--------------------
type float = System.Double
--------------------
type float<'Measure> = float
<summary> Returns the average of all elements of the task sequence. The elements must support the <c>+</c> operator and <c>DivideByInt</c>, which is the case for all built-in F# floating-point types. For sequences with a projection, consider using <see cref="TaskSeq.averageBy" />. </summary>
<param name="source">The input task sequence.</param>
<returns>The average of the elements in the sequence.</returns>
<exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
<exception cref="T:ArgumentException">Thrown when the input task sequence is empty.</exception>
<summary> Returns the sum of the results generated by applying the <paramref name="projection" /> function to each element of the task sequence. The result type must support the <c>+</c> operator, which is the case for all built-in numeric types. If <paramref name="projection" /> is asynchronous, consider using <see cref="TaskSeq.sumByAsync" />. </summary>
<param name="projection">A function to transform items from the input sequence into summable values.</param>
<param name="source">The input task sequence.</param>
<returns>The sum of the projected values.</returns>
<exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
FSharp.Control.TaskSeq