diff --git a/README.md b/README.md index 5195cfd1..4a4c7b49 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,47 @@ # TaskSeq An implementation `IAsyncEnumerableM<'T>` as a `taskSeq` CE for F# with accompanying `TaskSeq` module. -## Coming up!!! +## In progress!!! It's based on [Don Symes `taskSeq.fs`](https://github.com/dotnet/fsharp/blob/d5312aae8aad650f0043f055bb14c3aa8117e12e/tests/benchmarks/CompiledCodeBenchmarks/TaskPerf/TaskPerf/taskSeq.fs) but expanded with useful utility functions and a few extra binding overloads. + +## Current set of `TaskSeq` utility functions + +The following is the current surface area of the `TaskSeq` utility functions. This is just a dump of the signatures, proper +documentation will be added soon(ish): + +```f# +module TaskSeq = + val toList: t: taskSeq<'T> -> 'T list + val toArray: taskSeq: taskSeq<'T> -> 'T[] + val empty<'T> : IAsyncEnumerable<'T> + val ofArray: array: 'T[] -> IAsyncEnumerable<'T> + val ofList: list: 'T list -> IAsyncEnumerable<'T> + val ofSeq: sequence: seq<'T> -> IAsyncEnumerable<'T> + val ofResizeArray: data: ResizeArray<'T> -> IAsyncEnumerable<'T> + val ofTaskSeq: sequence: seq<#Task<'T>> -> IAsyncEnumerable<'T> + val ofTaskList: list: #Task<'T> list -> IAsyncEnumerable<'T> + val ofTaskArray: array: #Task<'T> array -> IAsyncEnumerable<'T> + val ofAsyncSeq: sequence: seq> -> IAsyncEnumerable<'T> + val ofAsyncList: list: Async<'T> list -> IAsyncEnumerable<'T> + val ofAsyncArray: array: Async<'T> array -> IAsyncEnumerable<'T> + val toArrayAsync: taskSeq: taskSeq<'a> -> Task<'a[]> + val toListAsync: taskSeq: taskSeq<'a> -> Task<'a list> + val toResizeArrayAsync: taskSeq: taskSeq<'a> -> Task> + val toIListAsync: taskSeq: taskSeq<'a> -> Task> + val toSeqCachedAsync: taskSeq: taskSeq<'a> -> Task> + val iter: action: ('a -> unit) -> taskSeq: taskSeq<'a> -> Task + val iteri: action: (int -> 'a -> unit) -> taskSeq: taskSeq<'a> -> Task + val iterAsync: action: ('a -> #Task) -> taskSeq: taskSeq<'a> -> Task + val iteriAsync: action: (int -> 'a -> #Task) -> taskSeq: taskSeq<'a> -> Task + val map: mapper: ('T -> 'U) -> taskSeq: taskSeq<'T> -> IAsyncEnumerable<'U> + val mapi: mapper: (int -> 'T -> 'U) -> taskSeq: taskSeq<'T> -> IAsyncEnumerable<'U> + val mapAsync: mapper: ('a -> #Task<'c>) -> taskSeq: taskSeq<'a> -> IAsyncEnumerable<'c> + val mapiAsync: mapper: (int -> 'a -> #Task<'c>) -> taskSeq: taskSeq<'a> -> IAsyncEnumerable<'c> + val collect: binder: ('T -> #IAsyncEnumerable<'U>) -> taskSeq: taskSeq<'T> -> IAsyncEnumerable<'U> + val collectSeq: binder: ('T -> #seq<'U>) -> taskSeq: taskSeq<'T> -> IAsyncEnumerable<'U> + val collectAsync: binder: ('T -> #Task<'b>) -> taskSeq: taskSeq<'T> -> taskSeq<'U> when 'b :> IAsyncEnumerable<'U> + val collectSeqAsync: binder: ('T -> #Task<'b>) -> taskSeq: taskSeq<'T> -> taskSeq<'U> when 'b :> seq<'U> + val zip: taskSeq1: taskSeq<'a> -> taskSeq2: taskSeq<'b> -> IAsyncEnumerable<'a * 'b> +``` diff --git a/src/FSharpy.TaskSeq/TaskSeq.fs b/src/FSharpy.TaskSeq/TaskSeq.fs index a9d14a21..76505102 100644 --- a/src/FSharpy.TaskSeq/TaskSeq.fs +++ b/src/FSharpy.TaskSeq/TaskSeq.fs @@ -9,7 +9,7 @@ module TaskSeq = open FSharpy.TaskSeqBuilders // Just for convenience - module Internal = FSharpy.TaskSeqInternal + module Internal = TaskSeqInternal /// Returns taskSeq as an array. This function is blocking until the sequence is exhausted. let toList (t: taskSeq<'T>) = [ @@ -132,32 +132,32 @@ module TaskSeq = // iter/map/collect functions // - /// Iterates over the taskSeq. This function is non-blocking + /// Iterates over the taskSeq applying the action function to each item. This function is non-blocking /// exhausts the sequence as soon as the task is evaluated. let iter action taskSeq = Internal.iter (SimpleAction action) taskSeq - /// Iterates over the taskSeq. This function is non-blocking, + /// Iterates over the taskSeq applying the action function to each item. This function is non-blocking, /// exhausts the sequence as soon as the task is evaluated. let iteri action taskSeq = Internal.iter (CountableAction action) taskSeq - /// Iterates over the taskSeq. This function is non-blocking + /// Iterates over the taskSeq applying the async action to each item. This function is non-blocking /// exhausts the sequence as soon as the task is evaluated. let iterAsync action taskSeq = Internal.iter (AsyncSimpleAction action) taskSeq - /// Iterates over the taskSeq. This function is non-blocking, + /// Iterates over the taskSeq, applying the async action to each item. This function is non-blocking, /// exhausts the sequence as soon as the task is evaluated. let iteriAsync action taskSeq = Internal.iter (AsyncCountableAction action) taskSeq - /// Maps over the taskSeq. This function is non-blocking. + /// Maps over the taskSeq, applying the mapper function to each item. This function is non-blocking. let map (mapper: 'T -> 'U) taskSeq = Internal.map (SimpleAction mapper) taskSeq - /// Maps over the taskSeq with an index. This function is non-blocking. + /// Maps over the taskSeq with an index, applying the mapper function to each item. This function is non-blocking. let mapi (mapper: int -> 'T -> 'U) taskSeq = Internal.map (CountableAction mapper) taskSeq - /// Maps over the taskSeq. This function is non-blocking. + /// Maps over the taskSeq, applying the async mapper function to each item. This function is non-blocking. let mapAsync mapper taskSeq = Internal.map (AsyncSimpleAction mapper) taskSeq - /// Maps over the taskSeq with an index. This function is non-blocking. + /// Maps over the taskSeq with an index, applying the async mapper function to each item. This function is non-blocking. let mapiAsync mapper taskSeq = Internal.map (AsyncCountableAction mapper) taskSeq /// Applies the given function to the items in the taskSeq and concatenates all the results in order. @@ -166,6 +166,13 @@ module TaskSeq = /// Applies the given function to the items in the taskSeq and concatenates all the results in order. let collectSeq (binder: 'T -> #seq<'U>) taskSeq = Internal.collectSeq binder taskSeq + /// Applies the given async function to the items in the taskSeq and concatenates all the results in order. + let collectAsync (binder: 'T -> #Task<#IAsyncEnumerable<'U>>) taskSeq : taskSeq<'U> = + Internal.collectAsync binder taskSeq + + /// Applies the given async function to the items in the taskSeq and concatenates all the results in order. + let collectSeqAsync (binder: 'T -> #Task<#seq<'U>>) taskSeq : taskSeq<'U> = Internal.collectSeqAsync binder taskSeq + // // zip/unzip etc functions // diff --git a/src/FSharpy.TaskSeq/TaskSeqInternal.fs b/src/FSharpy.TaskSeq/TaskSeqInternal.fs index 0e0c4076..0c98527f 100644 --- a/src/FSharpy.TaskSeq/TaskSeqInternal.fs +++ b/src/FSharpy.TaskSeq/TaskSeqInternal.fs @@ -80,7 +80,7 @@ module internal TaskSeqInternal = return res } - let inline toResizeArrayAndMapAsync mapper taskSeq = (toResizeArrayAsync >> Task.map mapper) taskSeq + let toResizeArrayAndMapAsync mapper taskSeq = (toResizeArrayAsync >> Task.map mapper) taskSeq let map mapper (taskSequence: taskSeq<_>) = match mapper with @@ -143,6 +143,18 @@ module internal TaskSeqInternal = yield! binder c :> seq<_> } + let collectAsync (binder: _ -> #Task<#IAsyncEnumerable<_>>) (taskSequence: taskSeq<_>) = taskSeq { + for c in taskSequence do + let! result = binder c + yield! result :> IAsyncEnumerable<_> + } + + let collectSeqAsync (binder: _ -> #Task<#seq<_>>) (taskSequence: taskSeq<_>) = taskSeq { + for c in taskSequence do + let! result = binder c + yield! result :> seq<_> + } + /// Returns taskSeq as an array. This function is blocking until the sequence is exhausted. let toListResult (t: taskSeq<'T>) = [ let e = t.GetAsyncEnumerator(CancellationToken())