From 7253a0f6ae904e76903181631a9a225241cb7e52 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sat, 5 Nov 2022 01:49:41 +0100 Subject: [PATCH 1/3] Add implementation progress --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 159c754c..e2cbaf94 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,21 @@ [![test][teststatus_img]][teststatus] # TaskSeq + An implementation [`IAsyncEnumerable<'T>`][3] as a `taskSeq` CE for F# with accompanying `TaskSeq` module. 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, where each page is a [`MoveNextAsync`][4] call on the [`IAsyncEnumerator<'T>`][5] given by a call to [`GetAsyncEnumerator()`][6]. It has been relatively challenging to work properly with this type and dealing with each step being asynchronous, and the enumerator implementing [`IAsyncDisposable`][7] as well, which requires careful handling. +## Implementation progress + +The _resumable state machine_ backing the `taskSeq` CE is considered stable. While bugs are always possible, we will mostly focus on adding functionality there, like adding more useful overloads for `yield` and `let!`. Suggestions are welcome! + +We are working hard on getting a full set of module functions on `TaskSeq` that can be used with `IAsyncEnumerable` sequences. Our guide is the set of F# `Seq` functions in F# Core and, where applicable, the functions provided from `AsyncSeq`. Each implemented function is documented through XML doc comments to provide the necessary context-sensitive help. + +The following is the progress report: + +TODO! + ### Futher reading `IAsyncEnumerable` * A good C#-based introduction [can be found in this blog][8]. @@ -33,10 +44,10 @@ TLDR: just run `build`. Or load the `sln` file in Visual Studio or VS Code and c ### Prerequisites * .NET 6 or .NET 7 Preview -* F# 6.0 compiler +* F# 6.0 or 7.0 compiler * To use `build.cmd`, the `dotnet` command must be accessible from your path. -Just checkout this repo locally. Then, from the root of the repo, you can do: +Just check-out this repo locally. Then, from the root of the repo, you can do: ### Build the solution From ea4946c8351f0fdee145d237719c3f87e528d8d4 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sat, 5 Nov 2022 03:35:57 +0100 Subject: [PATCH 2/3] Add progress overview and some reorganization --- README.md | 152 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 138 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index e2cbaf94..c0d430b9 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,151 @@ An implementation [`IAsyncEnumerable<'T>`][3] as a `taskSeq` CE for F# with acco 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, where each page is a [`MoveNextAsync`][4] call on the [`IAsyncEnumerator<'T>`][5] given by a call to [`GetAsyncEnumerator()`][6]. It has been relatively challenging to work properly with this type and dealing with each step being asynchronous, and the enumerator implementing [`IAsyncDisposable`][7] as well, which requires careful handling. +## Short-term feature planning + +Not necessarily in order of importance: + +* [x] Stabilize and battle-test `taskSeq` resumable code. **DONE** +* [x] A growing set of module functions `TaskSeq`, see below for progress. **DONE & IN PROGRESS** +* [ ] Packaging and publishing on Nuget, **PLANNED: 13 November 2022**. +* [x] Add `Async` variants for functions taking HOF arguments. **DONE** +* [ ] Expand surface area based on `AsyncSeq`. +* [ ] User requests? + ## Implementation progress -The _resumable state machine_ backing the `taskSeq` CE is considered stable. While bugs are always possible, we will mostly focus on adding functionality there, like adding more useful overloads for `yield` and `let!`. Suggestions are welcome! +### `taskSeq` CE + +The _resumable state machine_ backing the `taskSeq` CE is now finished. Focus is now on adding functionality there, like adding more useful overloads for `yield` and `let!`. Suggestions are welcome! + +### `TaskSeq` module functions We are working hard on getting a full set of module functions on `TaskSeq` that can be used with `IAsyncEnumerable` sequences. Our guide is the set of F# `Seq` functions in F# Core and, where applicable, the functions provided from `AsyncSeq`. Each implemented function is documented through XML doc comments to provide the necessary context-sensitive help. The following is the progress report: -TODO! +| Implemented | `Seq` function | `TaskSeq` function | Extra `async` variant | Remarks | +|---------------|--------------------|--------------------|-----------------------|-------------------------------------------| +| | `allPairs` | `allPairs` | | | +| | `append` | `append` | | | +| | `average` | `averageBy` | `averageByAsync` | | +| | `cache` | `cache` | | | +| ✅ | `cast` | `cast` | | | +| ✅ | | `box` | | | +| ✅ | | `unbox` | | | +| ✅ | `choose` | `choose` | `chooseAsync` | | +| | `chunkBySize` | `chunkBySize` | | | +| ✅ | `collect` | `collect` | `collectAsync` | | +| | `compareWith` | `compareWith` | `compareWithAsync` | | +| ✅ | `concat` | `concat` | | | +| ✅ | `contains` | `contains` | | | +| | `delay` | `delay` | | | +| | `distinct` | `distinct` | | | +| | `distinctBy` | `dictinctBy` | `distinctByAsync` | | +| ✅ | `empty` | `empty` | | | +| ✅ | `exactlyOne` | `exactlyOne` | | | +| | `except` | `except` | | | +| ✅ | `exists` | `exists` | | | +| | `exists2` | `exists2` | | | +| ✅ | `filter` | `filter` | `filterAsync` | | +| ✅ | `find` | `find` | `findAsync` | | +| _not planned_ | `findBack` | | | _iteration from back not possible_ | +| ✅ | `findIndex` | `findIndex` | `findIndexAsync` | | +| _not planned_ | `findIndexBack` | n/a | n/a | _iteration from back not possible_ | +| ✅ | `fold` | `fold` | `foldAsync` | | +| | `fold2` | `fold2` | `fold2Async` | | +| _not planned_ | `foldBack` | | | _iteration from back not possible_ | +| _not planned_ | `foldBack2` | | | _iteration from back not possible_ | +| | `forall` | `forall` | `forallAsync` | | +| | `forall2` | `forall2` | `forall2Async` | | +| _maybe_ | `groupBy` | `groupBy` | `groupByAsync` | | +| ✅ | `head` | `head` | | | +| ✅ | `indexed` | `indexed` | | | +| ✅ | `init` | `init` | `initAsync` | | +| ✅ | `initInfinite` | `initInfinite` | `initInfiniteAsync` | | +| | `insertAt` | `insertAt` | | | +| | `insertManyAt` | `insertManyAt` | | | +| ✅ | `isEmpty` | `isEmpty` | | | +| ✅ | `item` | `item` | | | +| ✅ | `iter` | `iter` | `iterAsync` | | +| | `iter2` | `iter2` | `iter2Async` | | +| ✅ | `iteri` | `iteri` | `iteriAsync` | | +| | `iteri2` | `iteri2` | `iteri2Async` | | +| ✅ | `last` | `last` | | | +| ✅ | `length` | `length` | | | +| ✅ | | `lengthBy` | `lengthByAsyn` | | +| ✅ | `map` | `map` | `mapAsync` | | +| | `map2` | `map2` | `map2Async` | | +| | `map3` | `map3` | `map3Async` | | +| | `mapFold` | `mapFold` | `mapFoldAsync` | | +| _not planned_ | `mapFoldBack` | | | _iteration from back not possible_ | +| ✅ | `mapi` | `mapi` | `mapiAsync` | | +| | `mapi2` | `mapi2` | `mapi2Async` | | +| | `max` | `max` | | | +| | `maxBy` | `maxBy` | `maxByAsync` | | +| | `min` | `min` | | | +| | `minBy` | `minBy` | `minByAsync` | | +| ✅ | `ofArray` | `ofArray` | | | +| ✅ | | `ofAsyncArray` | | | +| ✅ | | `ofAsyncList` | | | +| ✅ | | `ofAsyncSeq` | | | +| ✅ | `ofList` | `ofList` | | | +| ✅ | | `ofTaskList` | | | +| ✅ | | `ofResizeArray` | | | +| ✅ | | `ofSeq` | | | +| ✅ | | `ofTaskArray` | | | +| ✅ | | `ofTaskList` | | | +| ✅ | | `ofTaskSeq` | | | +| | `pairwise` | `pairwise` | | | +| | `permute` | `permute` | `permuteAsync` | | +| ✅ | `pick` | `pick` | `pickAsync` | | +| _not planned_ | `readOnly` | | | _all TaskSeq sequences are readonly_ | +| | `reduce` | `reduce` | `reduceAsync` | | +| _not planned_ | `reduceBack` | | | _iteration from back not possible_ | +| | `removeAt` | `removeAt` | | | +| | `removeManyAt` | `removeManyAt` | | | +| | `replicate` | `replicate` | | | +| _maybe_ | `rev` | | | | +| | `scan` | `scan` | `scanAsync` | | +| _not planned_ | `scanBack` | | | _iteration from back not possible_ | +| | `singleton` | `singleton` | | | +| | `skip` | `skip` | | | +| | `skipWhile` | `skipWhile` | `skipWhileAsync` | | +| _maybe_ | `sort` | | | | +| _maybe_ | `sortBy` | | | | +| _maybe_ | `sortByAscending` | | | | +| _maybe_ | `sortByDescending` | | | | +| _maybe_ | `sortWith` | | | | +| | `splitInto` | `splitInto` | | | +| | `sum` | `sum` | | | +| | `sumBy` | `sumBy` | `sumByAsync` | | +| | `tail` | `tail` | | | +| | `take` | `take` | | | +| | `takeWhile` | `takeWhile` | `takeWhileAsync` | | +| ✅ | `toArray` | `toArray` | `toArrayAsync` | | +| ✅ | | `toIList` | `toIListAsync` | | +| ✅ | `toList` | `toList` | `toListAsync` | | +| ✅ | | `toResizeArray` | `toResizeArrayAsync` | | +| ✅ | | `toSeq` | `toSeqAsync` | | +| | | […] | | _more convenience conversions considered_ | +| _maybe_ | `transpose` | | | | +| | `truncate` | `truncate` | | | +| ✅ | `tryExactlyOne` | `tryExactlyOne` | `tryExactlyOneAsync` | | +| ✅ | `tryFind` | `tryFind` | `tryFindAsync` | | +| _not planned_ | `tryFindBack` | | | _iteration from back not possible_ | +| ✅ | `tryFindIndex` | `tryFindIndex` | `tryFindIndexAsync` | | +| _not planned_ | `tryFindIndexBack` | | | _iteration from back not possible_ | +| ✅ | `tryHead` | `tryHead` | | | +| ✅ | `tryItem` | `tryItem` | | | +| ✅ | `tryLast` | `tryLast` | | | +| ✅ | `tryPick` | `tryPick` | `tryPickAsync` | | +| | `unfold` | `unfold` | `unfoldAsync` | | +| | `updateAt` | `updateAt` | | | +| | `where` | `where` | `whereAsync` | | +| | `windowed` | `windowed` | | | +| ✅ | `zip` | `zip` | | | +| | `zip3` | `zip3` | | | +| | | `zip4` | ### Futher reading `IAsyncEnumerable` @@ -106,18 +242,6 @@ For more info, see this PR: https://github.com/abelbraaksma/TaskSeq/pull/29. It's based on [Don Symes `taskSeq.fs`][20] but expanded with useful utility functions and a few extra binding overloads. -## Short-term feature planning - -Not necessarily in order of importance: - - - [x] A minimal base set of useful functions and sensible CE overloads, like `map`, `collect`, `fold`, `zip`. These functions will live in the module `TaskSeq`. The CE will be called `taskSeq`. - - [ ] Packaging and publishing on Nuget - - [ ] Provide the same surface area of functions as `Seq` in F# Core - - [ ] For each function, have a "normal" function, where the operator is non-async, and an async version. I.e., `TaskSeq.map` and `TaskSeq.mapAsync`, the difference being that the `mapper` function returns a `#Task<'T>` in the second version. - - [ ] Examples, documentation and tests - - [ ] Expand surface area based on user requests - - [ ] Improving the original code, adding benchmarks, and what have you. - ## 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 with doc comments From e677d43241af82135dd136057b4ccad2c3adaa3b Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sat, 5 Nov 2022 03:42:57 +0100 Subject: [PATCH 3/3] Add TOC --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index c0d430b9..19ab22e7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,29 @@ An implementation [`IAsyncEnumerable<'T>`][3] as a `taskSeq` CE for F# with acco 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, where each page is a [`MoveNextAsync`][4] call on the [`IAsyncEnumerator<'T>`][5] given by a call to [`GetAsyncEnumerator()`][6]. It has been relatively challenging to work properly with this type and dealing with each step being asynchronous, and the enumerator implementing [`IAsyncDisposable`][7] as well, which requires careful handling. +----------------------------------------- + +## Table of contents + +- [Short-term feature planning](#short-term-feature-planning) +- [Implementation progress](#implementation-progress) + - [`taskSeq` CE](#taskseq-ce) + - [`TaskSeq` module functions](#taskseq-module-functions) + - [Futher reading `IAsyncEnumerable`](#futher-reading-iasyncenumerable) + - [Futher reading on resumable state machines](#futher-reading-on-resumable-state-machines) + - [Further reading on computation expressions](#further-reading-on-computation-expressions) +- [Building & testing](#building--testing) + - [Prerequisites](#prerequisites) + - [Build the solution](#build-the-solution) + - [Run the tests](#run-the-tests) + - [Run the CI command](#run-the-ci-command) + - [Advanced](#advanced) + - [Get help (duh!)](#get-help-duh) +- [In progress!!!](#in-progress) +- [Current set of `TaskSeq` utility functions](#current-set-of-taskseq-utility-functions) + +----------------------------------------- + ## Short-term feature planning Not necessarily in order of importance: @@ -15,6 +38,7 @@ Not necessarily in order of importance: * [x] A growing set of module functions `TaskSeq`, see below for progress. **DONE & IN PROGRESS** * [ ] Packaging and publishing on Nuget, **PLANNED: 13 November 2022**. * [x] Add `Async` variants for functions taking HOF arguments. **DONE** +* [ ] Add generated docs to * [ ] Expand surface area based on `AsyncSeq`. * [ ] User requests?