Header menu logo FSharp.Control.TaskSeq

Transforming Task Sequences

This page covers the core operations for transforming TaskSeq<'T> values: map, filter, choose, collect, indexed, and type conversions. For operations that consume a sequence into a single result, see Consuming Sequences.

open System.Threading.Tasks
open FSharp.Control

Transforming with a computation expression

The most flexible way to transform a task sequence is to write a function that accepts a TaskSeq<_> and returns a TaskSeq<_> using a taskSeq { ... } computation expression. The for loop inside the CE is an asynchronous loop that awaits each element:

let labelEvenOdd (input: TaskSeq<int>) : TaskSeq<string> =
    taskSeq {
        for n in input do
            if n % 2 = 0 then
                do! Task.Delay 10 // simulate async work
                yield $"Even: {n}"
            else
                yield $"Odd: {n}"
    }

Inside taskSeq { ... } you can freely mix synchronous logic, let!/do! awaits, loops, and conditionals.


map and mapAsync

TaskSeq.map applies a synchronous function to every element:

let numbers : TaskSeq<int> = TaskSeq.ofSeq (seq { 1..5 })

let doubled : TaskSeq<int> = numbers |> TaskSeq.map (fun n -> n * 2)

TaskSeq.mapAsync is the same but the projection returns Task<'U>, allowing async work per element — for example, a database lookup or HTTP request:

let fetchDescription (n: int) : Task<string> =
    task { return $"item {n}" } // placeholder for a real async call

let descriptions : TaskSeq<string> = numbers |> TaskSeq.mapAsync fetchDescription

mapi and mapiAsync

TaskSeq.mapi and TaskSeq.mapiAsync additionally pass the zero-based index to the mapper:

let indexed : TaskSeq<string> =
    numbers |> TaskSeq.mapi (fun i n -> $"[{i}] {n}")

filter and filterAsync

TaskSeq.filter keeps only elements satisfying a synchronous predicate:

let evens : TaskSeq<int> = numbers |> TaskSeq.filter (fun n -> n % 2 = 0)

TaskSeq.filterAsync does the same with an async predicate — useful when the keep/discard decision requires an async lookup:

let isInteresting (n: int) : Task<bool> =
    task { return n > 2 } // placeholder

let interesting : TaskSeq<int> = numbers |> TaskSeq.filterAsync isInteresting

TaskSeq.where and TaskSeq.whereAsync are aliases for filter and filterAsync provided for readability.


choose and chooseAsync

TaskSeq.choose applies a function that returns 'U option; only Some values are kept and the option wrapper is removed — it is equivalent to filter + map in a single pass:

let strings : TaskSeq<string> =
    TaskSeq.ofList [ ""; "hello"; ""; "world" ]

let nonEmpty : TaskSeq<string> =
    strings
    |> TaskSeq.choose (fun s ->
        if s.Length > 0 then Some s else None)

TaskSeq.chooseAsync accepts an async chooser:

let parseAsync (s: string) : Task<int option> =
    task {
        match System.Int32.TryParse s with
        | true, n -> return Some n
        | _ -> return None
    }

let parsed : TaskSeq<int> =
    TaskSeq.ofList [ "1"; "two"; "3" ]
    |> TaskSeq.chooseAsync parseAsync

collect and collectSeq

TaskSeq.collect is the monadic bind for TaskSeq: it maps each element to a new task sequence and concatenates all the results end-to-end:

let words : TaskSeq<string> =
    TaskSeq.ofList [ "foo bar"; "baz qux" ]

let chars : TaskSeq<string> =
    words
    |> TaskSeq.collectSeq (fun sentence ->
        sentence.Split(' ') |> Array.toSeq)

TaskSeq.collect maps to another TaskSeq<'U>, while TaskSeq.collectSeq maps to a plain seq<'U>. Async variants TaskSeq.collectAsync and TaskSeq.collectSeqAsync accept mappers that return tasks.


indexed

TaskSeq.indexed pairs each element with its zero-based index, returning a TaskSeq<int * 'T>:

let withIndex : TaskSeq<int * string> =
    TaskSeq.ofList [ "a"; "b"; "c" ] |> TaskSeq.indexed

// yields (0,"a"), (1,"b"), (2,"c")

Type conversions

TaskSeq.cast casts items from TaskSeq<obj> to a target reference type. For value types use TaskSeq.unbox:

let boxed : TaskSeq<obj> =
    TaskSeq.ofList [ box 1; box 2; box 3 ]

let unboxed : TaskSeq<int> = boxed |> TaskSeq.unbox<int>

let castToString : TaskSeq<string> =
    TaskSeq.ofList [ box "hello"; box "world" ]
    |> TaskSeq.cast<string>
namespace System
namespace System.Threading
namespace System.Threading.Tasks
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Control

--------------------
namespace Microsoft.FSharp.Control
val labelEvenOdd: input: TaskSeq<int> -> TaskSeq<string>
val input: TaskSeq<int>
Multiple items
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&lt;_&gt;" />. </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&lt;'T&gt;" /> 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>
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val taskSeq: TaskSeqBuilder
<summary> Builds an asynchronous task sequence based on <see cref="IAsyncEnumerable&lt;'T&gt;" /> using computation expression syntax. </summary>
val n: int
Multiple items
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.Delay(delay: System.TimeSpan) : Task
Task.Delay(millisecondsDelay: int) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider) : Task
Task.Delay(delay: System.TimeSpan, cancellationToken: System.Threading.CancellationToken) : Task
Task.Delay(millisecondsDelay: int, cancellationToken: System.Threading.CancellationToken) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider, cancellationToken: System.Threading.CancellationToken) : Task
val numbers: TaskSeq<int>
static member TaskSeq.ofSeq: source: 'T seq -> TaskSeq<'T>
Multiple items
val seq: sequence: 'T seq -> 'T seq

--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
val doubled: TaskSeq<int>
static member TaskSeq.map: mapper: ('T -> 'U) -> source: TaskSeq<'T> -> TaskSeq<'U>
val fetchDescription: n: int -> Task<string>
val task: TaskBuilder
val descriptions: TaskSeq<string>
static member TaskSeq.mapAsync: mapper: ('T -> #Task<'U>) -> source: TaskSeq<'T> -> TaskSeq<'U>
val indexed: TaskSeq<string>
static member TaskSeq.mapi: mapper: (int -> 'T -> 'U) -> source: TaskSeq<'T> -> TaskSeq<'U>
val i: int
val evens: TaskSeq<int>
static member TaskSeq.filter: predicate: ('T -> bool) -> source: TaskSeq<'T> -> TaskSeq<'T>
val isInteresting: n: int -> Task<bool>
type bool = System.Boolean
val interesting: TaskSeq<int>
static member TaskSeq.filterAsync: predicate: ('T -> #Task<bool>) -> source: TaskSeq<'T> -> TaskSeq<'T>
val strings: TaskSeq<string>
static member TaskSeq.ofList: source: 'T list -> TaskSeq<'T>
val nonEmpty: TaskSeq<string>
static member TaskSeq.choose: chooser: ('T -> 'U option) -> source: TaskSeq<'T> -> TaskSeq<'U>
val s: string
property System.String.Length: int with get
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val parseAsync: s: string -> Task<int option>
type 'T option = Option<'T>
[<Struct>] type Int32 = member CompareTo: value: int -> int + 1 overload member Equals: obj: int -> bool + 1 overload member GetHashCode: unit -> int member GetTypeCode: unit -> TypeCode member ToString: unit -> string + 3 overloads member TryFormat: utf8Destination: Span<byte> * bytesWritten: byref<int> * ?format: ReadOnlySpan<char> * ?provider: IFormatProvider -> bool + 1 overload static member Abs: value: int -> int static member BigMul: left: int * right: int -> int64 static member Clamp: value: int * min: int * max: int -> int static member CopySign: value: int * sign: int -> int ...
<summary>Represents a 32-bit signed integer.</summary>
System.Int32.TryParse([<NotNullWhenAttribute (true)>] s: string, result: byref<int>) : bool
System.Int32.TryParse(s: System.ReadOnlySpan<char>, result: byref<int>) : bool
System.Int32.TryParse(utf8Text: System.ReadOnlySpan<byte>, result: byref<int>) : bool
System.Int32.TryParse([<NotNullWhenAttribute (true)>] s: string, provider: System.IFormatProvider, result: byref<int>) : bool
System.Int32.TryParse(s: System.ReadOnlySpan<char>, provider: System.IFormatProvider, result: byref<int>) : bool
System.Int32.TryParse(utf8Text: System.ReadOnlySpan<byte>, provider: System.IFormatProvider, result: byref<int>) : bool
System.Int32.TryParse([<NotNullWhenAttribute (true)>] s: string, style: System.Globalization.NumberStyles, provider: System.IFormatProvider, result: byref<int>) : bool
System.Int32.TryParse(s: System.ReadOnlySpan<char>, style: System.Globalization.NumberStyles, provider: System.IFormatProvider, result: byref<int>) : bool
System.Int32.TryParse(utf8Text: System.ReadOnlySpan<byte>, style: System.Globalization.NumberStyles, provider: System.IFormatProvider, result: byref<int>) : bool
val parsed: TaskSeq<int>
static member TaskSeq.chooseAsync: chooser: ('T -> #Task<'U option>) -> source: TaskSeq<'T> -> TaskSeq<'U>
val words: TaskSeq<string>
val chars: TaskSeq<string>
static member TaskSeq.collectSeq: binder: ('T -> #('U seq)) -> source: TaskSeq<'T> -> TaskSeq<'U>
val sentence: string
System.String.Split(separator: System.ReadOnlySpan<char>) : string array
   (+0 other overloads)
System.String.Split([<System.ParamArray>] separator: char array) : string array
   (+0 other overloads)
System.String.Split(separator: string array, options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: string, ?options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: char array, options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: char array, count: int) : string array
   (+0 other overloads)
System.String.Split(separator: char, ?options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: string array, count: int, options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: string, count: int, ?options: System.StringSplitOptions) : string array
   (+0 other overloads)
System.String.Split(separator: char array, count: int, options: System.StringSplitOptions) : string array
   (+0 other overloads)
module Array from Microsoft.FSharp.Collections
val toSeq: array: 'T array -> 'T seq
val withIndex: TaskSeq<int * string>
static member TaskSeq.indexed: source: TaskSeq<'T> -> TaskSeq<int * 'T>
val boxed: TaskSeq<obj>
type obj = System.Object
val box: value: 'T -> objnull
val unboxed: TaskSeq<int>
static member TaskSeq.unbox: source: TaskSeq<obj> -> TaskSeq<'U> (requires value type)
val castToString: TaskSeq<string>
static member TaskSeq.cast: source: TaskSeq<obj> -> TaskSeq<'U>

Type something to start searching.