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 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 string: value: 'T -> string
--------------------
type string = System.String
<summary> Builds an asynchronous task sequence based on <see cref="IAsyncEnumerable<'T>" /> using computation expression syntax. </summary>
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(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 seq: sequence: 'T seq -> 'T seq
--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
<summary>Represents a 32-bit signed integer.</summary>
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
(+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)
FSharp.Control.TaskSeq