diff --git a/README.md b/README.md
index 13b7c26c..9cf9bcdd 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
# TaskSeq
-An implementation of [`IAsyncEnumerable<'T>`][3] as a computation expression: `taskSeq { ... }` with an accompanying `TaskSeq` module, that allows seamless use of asynchronous sequences similar to F#'s native `seq` and `task` CE's.
+An implementation of [`IAsyncEnumerable<'T>`][3] 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.
* Latest stable version: [0.3.0 is on NuGet][nuget].
* Latest prerelease version: [0.4.0-alpha.1 is on NuGet][nuget].
@@ -52,7 +52,7 @@ See [release notes.txt](release-notes.txt) for the version history of `TaskSeq`.
## 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 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`][4] call on the [`IAsyncEnumerator<'T>`][3] given by a call to [`GetAsyncEnumerator()`][6].
+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`][4] call on the [`IAsyncEnumerator<'T>`][3] given by a call to [`GetAsyncEnumerator()`][6].
Since the introduction of `task` in F# the call for a native implementation of _task sequences_ has grown, in particular because proper iteration over an `IAsyncEnumerable` has proven challenging, especially if one wants to avoid mutable variables. This library is an answer to that call and applies the same _resumable state machine_ approach with `taskSeq`.
@@ -92,7 +92,7 @@ F# Interactive (FSI):
> #r "nuget: FSharp.Control.TaskSeq"
// or with specific version
-> #r "nuget: FSharp.Control.TaskSeq, 0.2.2"
+> #r "nuget: FSharp.Control.TaskSeq, 0.4.0"
```
Paket:
@@ -111,7 +111,7 @@ As package reference in `fsproj` or `csproj` file:
```xml
-
+
```
### Examples
@@ -196,24 +196,48 @@ There are more differences:
| **[`Current`][5]** | [Returns `'T`][5] | n/a |
| **Cancellation** | See [#133][], until 0.3.0: use `GetAsyncEnumerator(cancelToken)` | Implicit token flows to all subtasks per `async` semantics |
| **Performance** | Very high, negligible allocations | Slower, more allocations, due to using `async` and cont style |
-| **Parallelism** | Possible with ChildTask; support will follow | Supported explicitly |
+| **Parallelism** | Unclear, interface is meant for _sequential/async_ processing | Supported by extension functions |
¹⁾ _Both `AsyncSeq` and `TaskSeq` use a type called `IAsyncEnumerable<'T>`, but only `TaskSeq` uses the type from the BCL Generic Collections. `AsyncSeq` supports .NET Framework 4.6.x and NetStandard 2.0 as well, which do not have this type in the BCL._
## Status & planning
-This project has stable features currently, but before we go full "version one", we'd like to complete the surface area. This section covers the status of that, with a full list of implemented functions below. Here's the shortlist:
-
-- [x] Stabilize and battle-test `taskSeq` resumable code. **DONE**
-- [x] A growing set of module functions `TaskSeq`, see below for progress. **DONE & IN PROGRESS**
-- [x] Packaging and publishing on Nuget, **DONE, PUBLISHED SINCE: 7 November 2022**. See https://www.nuget.org/packages/FSharp.Control.TaskSeq
-- [x] Add `Async` variants for functions taking HOF arguments. **DONE**
-- [ ] Add generated docs to
-- [ ] Expand surface area based on `AsyncSeq`. **ONGOING**
+The `TaskSeq` project already has a wide array of functions and functionalities, see overview below. The current status is: *STABLE*. However, certain features we'd really like to add:
+
+- [x] Take existing `taskSeq` resumable code from F# and fix it. **DONE**
+- [x] Add almost all functions from `Seq` that could apply to `TaskSeq` (full overview below). **MOSTLY DONE, STILL TODO**
+- [ ] Add remaining relevant functions from `Seq`. **PLANNED FOR 0.4.x**
+ - [x] `min` / `max` / `minBy` / `maxBy` & async variant (see [#221])
+ - [x] `insertAt` / `updateAt` and related (see [#236])
+ - [ ] `average` / `averageBy`, `sum` and related
+ - [x] `forall` / `forallAsync` (see [#240])
+ - [x] `skip` / `drop` / `truncate` / `take` (see [#209])
+ - [ ] `chunkBySize` / `windowed`
+ - [ ] `compareWith`
+ - [ ] `distinct`
+ - [ ] `exists2` / `map2` / `fold2` / `iter2` and related '2'-functions
+ - [ ] `mapFold`
+ - [ ] `pairwise` / `allpairs` / `permute` / `distinct` / `distinctBy`
+ - [ ] `replicate`
+ - [ ] `reduce` / `scan`
+ - [ ] `unfold`
+- [x] Publish package on Nuget, **DONE, PUBLISHED SINCE: 7 November 2022**. See https://www.nuget.org/packages/FSharp.Control.TaskSeq
+- [x] Make `TaskSeq` interoperable with `Task` by expanding the latter with a `for .. in .. do` that acceps task sequences
+- [x] Add to/from functions to seq, list, array
+- [ ] Add applicable functions from `AsyncSeq`. **PLANNED FOR 0.5-alpha**
+- [ ] (Better) support for cancellations
+ - [ ] Make the tasks cancellable with token (see [#133]). **PLANNED FOR 0.5-alpha**
+ - [ ] Support `ConfiguredCancelableAsyncEnumerable` (see [#167]). **PLANNED FOR 0.5-alpha**
+ - [ ] Interop with `cancellableTask` and `valueTask` from [`IcedTasks`][24]
+- [ ] Interop with `AsyncSeq`.
+- [ ] (maybe) Support any awaitable type in the function lib (that is: where a `Task` is required, accept a `ValueTask` and `Async` as well)
+- [ ] Add `TaskEx` functionality (separate lib). **DISCUSSION**
+- [ ] Move documentation to
### Implementation progress
-As of 9 November 2022: [Nuget package available][21]. In this phase, we will frequently update the package, see [release notes.txt](release-notes.txt). Current version:
+ * As of 9 November 2022: [Nuget package available][21]. In this phase, we will frequently update the package, see [release notes.txt](release-notes.txt). Current version:
+ * Major update: 17 March 2024, version 0.4.0
[](https://www.nuget.org/packages/FSharp.Control.TaskSeq/)
@@ -245,10 +269,15 @@ This is what has been implemented so far, is planned or skipped:
| ✅ [#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` | | |
@@ -264,15 +293,15 @@ This is what has been implemented so far, is planned or skipped:
| | `fold2` | `fold2` | `fold2Async` | |
| 🚫 | `foldBack` | | | [note #2](#note2 "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 'Back' iterators.") |
| 🚫 | `foldBack2` | | | [note #2](#note2 "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 'Back' iterators.") |
-| | `forall` | `forall` | `forallAsync` | |
+| ✅ [#240][]| `forall` | `forall` | `forallAsync` | |
| | `forall2` | `forall2` | `forall2Async` | |
| ❓ | `groupBy` | `groupBy` | `groupByAsync` | [note #1](#note1 "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.") |
| ✅ [#23][] | `head` | `head` | | |
| ✅ [#68][] | `indexed` | `indexed` | | |
| ✅ [#69][] | `init` | `init` | `initAsync` | |
| ✅ [#69][] | `initInfinite` | `initInfinite` | `initInfiniteAsync` | |
-| | `insertAt` | `insertAt` | | |
-| | `insertManyAt` | `insertManyAt` | | |
+| ✅ [#236][]| `insertAt` | `insertAt` | | |
+| ✅ [#236][]| `insertManyAt` | `insertManyAt` | | |
| ✅ [#23][] | `isEmpty` | `isEmpty` | | |
| ✅ [#23][] | `item` | `item` | | |
| ✅ [#2][] | `iter` | `iter` | `iterAsync` | |
@@ -310,15 +339,14 @@ This is what has been implemented so far, is planned or skipped:
| 🚫 | `readOnly` | | | [note #3](#note3 "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.") |
| | `reduce` | `reduce` | `reduceAsync` | |
| 🚫 | `reduceBack` | | | [note #2](#note2 "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 'Back' iterators.") |
-| | `removeAt` | `removeAt` | | |
-| | `removeManyAt` | `removeManyAt` | | |
+| ✅ [#236][]| `removeAt` | `removeAt` | | |
+| ✅ [#236][]| `removeManyAt` | `removeManyAt` | | |
| | `replicate` | `replicate` | | |
| ❓ | `rev` | | | [note #1](#note1 "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.") |
| | `scan` | `scan` | `scanAsync` | |
| 🚫 | `scanBack` | | | [note #2](#note2 "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 'Back' iterators.") |
| ✅ [#90][] | `singleton` | `singleton` | | |
| ✅ [#209][]| `skip` | `skip` | | |
-| ✅ [#209][]| | `drop` | | |
| ✅ [#219][]| `skipWhile` | `skipWhile` | `skipWhileAsync` | |
| ✅ [#219][]| | `skipWhileInclusive` | `skipWhileInclusiveAsync` | |
| ❓ | `sort` | | | [note #1](#note1 "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.") |
@@ -352,7 +380,7 @@ This is what has been implemented so far, is planned or skipped:
| ✅ [#23][] | `tryPick` | `tryPick` | `tryPickAsync` | |
| ✅ [#76][] | | `tryTail` | | |
| | `unfold` | `unfold` | `unfoldAsync` | |
-| | `updateAt` | `updateAt` | | |
+| ✅ [#236][]| `updateAt` | `updateAt` | | |
| ✅ [#217][]| `where` | `where` | `whereAsync` | |
| | `windowed` | `windowed` | | |
| ✅ [#2][] | `zip` | `zip` | | |
@@ -473,6 +501,10 @@ module TaskSeq =
val collectSeq: binder: ('T -> #seq<'U>) -> source: TaskSeq<'T> -> TaskSeq<'U>
val collectSeqAsync: binder: ('T -> #Task<'SeqU>) -> source: TaskSeq<'T> -> TaskSeq<'U> when 'SeqU :> seq<'U>
val concat: sources: TaskSeq<#TaskSeq<'T>> -> TaskSeq<'T>
+ val concat: sources: TaskSeq<'T seq> -> TaskSeq<'T>
+ val concat: sources: TaskSeq<'T list> -> TaskSeq<'T>
+ val concat: sources: TaskSeq<'T array> -> TaskSeq<'T>
+ val concat: sources: TaskSeq> -> TaskSeq<'T>
val contains<'T when 'T: equality> : value: 'T -> source: TaskSeq<'T> -> Task
val delay: generator: (unit -> TaskSeq<'T>) -> TaskSeq<'T>
val drop: count: int -> source: TaskSeq<'T> -> TaskSeq<'T>
@@ -490,12 +522,16 @@ module TaskSeq =
val findIndexAsync: predicate: ('T -> #Task) -> source: TaskSeq<'T> -> Task
val fold: folder: ('State -> 'T -> 'State) -> state: 'State -> source: TaskSeq<'T> -> Task<'State>
val foldAsync: folder: ('State -> 'T -> #Task<'State>) -> state: 'State -> source: TaskSeq<'T> -> Task<'State>
+ val forall: predicate: ('T -> bool) -> source: TaskSeq<'T> -> Task
+ val forallAsync: predicate: ('T -> #Task) -> source: TaskSeq<'T> -> Task
val head: source: TaskSeq<'T> -> Task<'T>
val indexed: source: TaskSeq<'T> -> TaskSeq
val init: count: int -> initializer: (int -> 'T) -> TaskSeq<'T>
val initAsync: count: int -> initializer: (int -> #Task<'T>) -> TaskSeq<'T>
val initInfinite: initializer: (int -> 'T) -> TaskSeq<'T>
val initInfiniteAsync: initializer: (int -> #Task<'T>) -> TaskSeq<'T>
+ val insertAt: position:int -> value:'T -> source: TaskSeq<'T> -> TaskSeq<'T>
+ val insertManyAt: position:int -> values:TaskSeq<'T> -> source: TaskSeq<'T> -> TaskSeq<'T>
val isEmpty: source: TaskSeq<'T> -> Task
val item: index: int -> source: TaskSeq<'T> -> Task<'T>
val iter: action: ('T -> unit) -> source: TaskSeq<'T> -> Task
@@ -529,6 +565,8 @@ module TaskSeq =
val pick: chooser: ('T -> 'U option) -> source: TaskSeq<'T> -> Task<'U>
val pickAsync: chooser: ('T -> #Task<'U option>) -> source: TaskSeq<'T> -> Task<'U>
val prependSeq: source1: seq<'T> -> source2: TaskSeq<'T> -> TaskSeq<'T>
+ val removeAt: position:int -> source: TaskSeq<'T> -> TaskSeq<'T>
+ val removeManyAt: position:int -> count:int -> source: TaskSeq<'T> -> TaskSeq<'T>
val singleton: source: 'T -> TaskSeq<'T>
val skip: count: int -> source: TaskSeq<'T> -> TaskSeq<'T>
val tail: source: TaskSeq<'T> -> Task>
@@ -559,6 +597,7 @@ module TaskSeq =
val where: predicate: ('T -> bool) -> source: TaskSeq<'T> -> TaskSeq<'T>
val whereAsync: predicate: ('T -> #Task) -> source: TaskSeq<'T> -> TaskSeq<'T>
val unbox<'U when 'U: struct> : source: TaskSeq -> TaskSeq<'U>
+ val updateAt: position:int -> value:'T -> source: TaskSeq<'T> -> TaskSeq<'T>
val zip: source1: TaskSeq<'T> -> source2: TaskSeq<'U> -> TaskSeq<'T * 'U>
```
@@ -590,6 +629,7 @@ module TaskSeq =
[21]: https://www.nuget.org/packages/FSharp.Control.TaskSeq#versions-body-tab
[22]: https://fsprojects.github.io/FSharp.Control.AsyncSeq/reference/fsharp-control-asyncseq.html#toAsyncEnum
[23]: https://fsprojects.github.io/FSharp.Control.AsyncSeq/reference/fsharp-control-asyncseq.html#fromAsyncEnum
+[24]: https://github.com/TheAngryByrd/IcedTasks
[#2]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/2
[#11]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/11
@@ -606,10 +646,14 @@ module TaskSeq =
[#90]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/90
[#126]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/126
[#133]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/133
+[#167]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/167
[#209]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/209
[#217]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/217
[#219]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/219
[#221]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/221
+[#237]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/237
+[#236]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/236
+[#240]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/240
[issues]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues
[nuget]: https://www.nuget.org/packages/FSharp.Control.TaskSeq/
diff --git a/Version.props b/Version.props
index 1b14afd5..2ec8b638 100644
--- a/Version.props
+++ b/Version.props
@@ -1,6 +1,6 @@
- 0.4.0-alpha.1
+ 0.4.0
\ No newline at end of file
diff --git a/assets/nuget-package-readme.md b/assets/nuget-package-readme.md
index ceaff83d..d0f89fe3 100644
--- a/assets/nuget-package-readme.md
+++ b/assets/nuget-package-readme.md
@@ -1,6 +1,6 @@
# TaskSeq
-An implementation of [`IAsyncEnumerable<'T>`][3] as a computation expression: `taskSeq { ... }` with an accompanying `TaskSeq` module, that allows seamless use of asynchronous sequences similar to F#'s native `seq` and `task` CE's.
+An implementation of [`IAsyncEnumerable<'T>`][3] 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][1].
@@ -30,7 +30,7 @@ A more extensive overview can be found in the [repository's readme][1].
## 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 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`][4] call on the [`IAsyncEnumerator<'T>`][5] given by a call to [`GetAsyncEnumerator()`][6].
+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`][4] call on the [`IAsyncEnumerator<'T>`][5] given by a call to [`GetAsyncEnumerator()`][6].
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`.
@@ -125,10 +125,15 @@ This is what has been implemented so far, is planned or skipped:
| ✅ [#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` | | |
@@ -144,15 +149,15 @@ This is what has been implemented so far, is planned or skipped:
| | `fold2` | `fold2` | `fold2Async` | |
| 🚫 | `foldBack` | | | [note #2](#note2 "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 'Back' iterators.") |
| 🚫 | `foldBack2` | | | [note #2](#note2 "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 'Back' iterators.") |
-| | `forall` | `forall` | `forallAsync` | |
+| ✅ [#240][]| `forall` | `forall` | `forallAsync` | |
| | `forall2` | `forall2` | `forall2Async` | |
| ❓ | `groupBy` | `groupBy` | `groupByAsync` | [note #1](#note1 "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.") |
| ✅ [#23][] | `head` | `head` | | |
| ✅ [#68][] | `indexed` | `indexed` | | |
| ✅ [#69][] | `init` | `init` | `initAsync` | |
| ✅ [#69][] | `initInfinite` | `initInfinite` | `initInfiniteAsync` | |
-| | `insertAt` | `insertAt` | | |
-| | `insertManyAt` | `insertManyAt` | | |
+| ✅ [#236][]| `insertAt` | `insertAt` | | |
+| ✅ [#236][]| `insertManyAt` | `insertManyAt` | | |
| ✅ [#23][] | `isEmpty` | `isEmpty` | | |
| ✅ [#23][] | `item` | `item` | | |
| ✅ [#2][] | `iter` | `iter` | `iterAsync` | |
@@ -190,15 +195,14 @@ This is what has been implemented so far, is planned or skipped:
| 🚫 | `readOnly` | | | [note #3](#note3 "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.") |
| | `reduce` | `reduce` | `reduceAsync` | |
| 🚫 | `reduceBack` | | | [note #2](#note2 "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 'Back' iterators.") |
-| | `removeAt` | `removeAt` | | |
-| | `removeManyAt` | `removeManyAt` | | |
+| ✅ [#236][]| `removeAt` | `removeAt` | | |
+| ✅ [#236][]| `removeManyAt` | `removeManyAt` | | |
| | `replicate` | `replicate` | | |
| ❓ | `rev` | | | [note #1](#note1 "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.") |
| | `scan` | `scan` | `scanAsync` | |
| 🚫 | `scanBack` | | | [note #2](#note2 "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 'Back' iterators.") |
| ✅ [#90][] | `singleton` | `singleton` | | |
| ✅ [#209][]| `skip` | `skip` | | |
-| ✅ [#209][]| | `drop` | | |
| ✅ [#219][]| `skipWhile` | `skipWhile` | `skipWhileAsync` | |
| ✅ [#219][]| | `skipWhileInclusive` | `skipWhileInclusiveAsync` | |
| ❓ | `sort` | | | [note #1](#note1 "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.") |
@@ -232,7 +236,7 @@ This is what has been implemented so far, is planned or skipped:
| ✅ [#23][] | `tryPick` | `tryPick` | `tryPickAsync` | |
| ✅ [#76][] | | `tryTail` | | |
| | `unfold` | `unfold` | `unfoldAsync` | |
-| | `updateAt` | `updateAt` | | |
+| ✅ [#236][]| `updateAt` | `updateAt` | | |
| ✅ [#217][]| `where` | `where` | `whereAsync` | |
| | `windowed` | `windowed` | | |
| ✅ [#2][] | `zip` | `zip` | | |
@@ -306,7 +310,13 @@ _The motivation for `readOnly` in `Seq` is that a cast from a mutable array or l
[#83]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/83
[#90]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/90
[#126]: https://github.com/fsprojects/FSharp.Control.TaskSeq/pull/126
+[#133]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/133
+[#167]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/167
[#209]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/209
[#217]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/217
[#219]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/219
[#221]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/221
+[#237]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/237
+[#236]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/236
+[#240]: https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/240
+
diff --git a/release-notes.txt b/release-notes.txt
index df20d858..7f0d630c 100644
--- a/release-notes.txt
+++ b/release-notes.txt
@@ -1,38 +1,43 @@
Release notes:
-0.4.x (unreleased)
- - overhaul all doc comments, add exceptions, improve IDE quick-info experience, #136
+0.4.0
+ - overhaul all doc comments, add exceptions, improve IDE quick-info experience, #136, #220, #234
- new surface area functions, fixes #208:
* TaskSeq.take, skip, #209
* TaskSeq.truncate, drop, #209
* TaskSeq.where, whereAsync, #217
* TaskSeq.skipWhile, skipWhileInclusive, skipWhileAsync, skipWhileInclusiveAsync, #219
* TaskSeq.max, min, maxBy, minBy, maxByAsync, minByAsync, #221
+ * TaskSeq.insertAt, insertManyAt, removeAt, removeManyAt, updateAt, #236
+ * TaskSeq.forall, forallAsync, #240
+ * TaskSeq.concat (overloads: seq, array, resizearray, list), #237
- Performance: less thread hops with 'StartImmediateAsTask' instead of 'StartAsTask', fixes #135
- - BINARY INCOMPATIBILITY: 'TaskSeq' module is now static members on 'TaskSeq<_>', fixes #184
+ - Performance: several inline and allocation improvements
+ - BINARY INCOMPATIBILITY: 'TaskSeq' module replaced by static members on 'TaskSeq<_>', fixes #184
- DEPRECATIONS (warning FS0044):
- type 'taskSeq<_>' is renamed to 'TaskSeq<_>', fixes #193
- function 'ValueTask.ofIValueTaskSource` renamed to `ValueTask.ofSource`, fixes #193
- function `ValueTask.FromResult` is renamed to `ValueTask.fromResult`, fixes #193
0.4.0-alpha.1
- - fixes not calling Dispose for 'use!', 'use', or `finally` blocks #157 (by @bartelink)
+ - bugfix: not calling Dispose for 'use!', 'use', or `finally` blocks #157 (by @bartelink)
- BREAKING CHANGE: null args now raise ArgumentNullException instead of NullReferenceException, #127
- adds `let!` and `do!` support for F#'s Async<'T>, #79, #114
- adds TaskSeq.takeWhile, takeWhileAsync, takeWhileInclusive, takeWhileInclusiveAsync, #126 (by @bartelink)
- adds AsyncSeq vs TaskSeq comparison chart, #131
- - removes release-notes.txt from file dependencies, but keep in the package, #138
+ - bugfix: removes release-notes.txt from file dependencies, but keep in the package, #138
0.3.0
- - internal renames, improved doc comments, signature files for complex types, hide internal-only types, fixes #112.
+ - improved xml doc comments, signature files for exposing types, fixes #112.
- adds support for static TaskLike, allowing the same let! and do! overloads that F# task supports, fixes #110.
- implements 'do!' for non-generic Task like with Task.Delay, fixes #43.
- - adds support for 'for .. in ..' with task sequences in F# tasks and async, #75, #93 and #99 (with help from @theangrybyrd).
+ - task and async CEs extended with support for 'for .. in ..do' with TaskSeq, #75, #93, #99 (in part by @theangrybyrd).
- adds TaskSeq.singleton, #90 (by @gusty).
- - fixes overload resolution bug with 'use' and 'use!', #97 (thanks @peterfaria).
+ - bugfix: fixes overload resolution bug with 'use' and 'use!', #97 (thanks @peterfaria).
- improves TaskSeq.empty by not relying on resumable state, #89 (by @gusty).
- - does not throw exceptions anymore for unequal lengths in TaskSeq.zip, fixes #32.
+ - bugfix: does not throw exceptions anymore for unequal lengths in TaskSeq.zip, fixes #32.
+ - BACKWARD INCOMPATIBILITY: several internal-only types now hidden
0.2.2
- removes TaskSeq.toSeqCachedAsync, which was incorrectly named. Use toSeq or toListAsync instead.
diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
index 297af81f..15cfdc69 100644
--- a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
+++ b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
@@ -13,7 +13,7 @@
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.
- Copyright 2023
+ Copyright 2022-2024
https://github.com/fsprojects/FSharp.Control.TaskSeq
https://github.com/fsprojects/FSharp.Control.TaskSeq
taskseq-icon.png
@@ -22,7 +22,7 @@ Generates optimized IL code through resumable state machines, and comes with a c
False
nuget-package-readme.md
$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../release-notes.txt"))
- taskseq;f#;computation expression;IAsyncEnumerable;task;async;asyncseq;
+ taskseq;f#;fsharp;asyncseq;seq;sequences;sequential;threading;computation expression;IAsyncEnumerable;task;async;iteration
True
snupkg