From a2ef3979684f23b1227abd8a6c2fc3697e7099cf Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Thu, 10 Nov 2022 04:18:04 +0100 Subject: [PATCH 1/2] Rename `TaskSeq.toSeqCached` -> `toSeq` and remove `TaskSeq.toSeqCachedAsync`, which simply didn't make much sense --- .../TaskSeq.Append.Tests.fs | 4 +- .../TaskSeq.Cast.Tests.fs | 4 +- .../TaskSeq.Collect.Tests.fs | 4 +- .../TaskSeq.Concat.Tests.fs | 4 +- .../TaskSeq.Delay.Tests.fs | 4 +- .../TaskSeq.Empty.Tests.fs | 2 +- .../TaskSeq.Map.Tests.fs | 8 ++-- .../TaskSeq.ToXXX.Tests.fs | 31 ++------------ src/FSharp.Control.TaskSeq.Test/TestUtils.fs | 4 +- .../FSharp.Control.TaskSeq.fsproj | 41 ++++++++++++++----- src/FSharp.Control.TaskSeq/TaskSeq.fs | 4 +- src/FSharp.Control.TaskSeq/TaskSeq.fsi | 16 +++++--- 12 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Append.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Append.Tests.fs index 0448acc7..629dd777 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Append.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Append.Tests.fs @@ -17,8 +17,8 @@ open System.Collections.Generic let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "1234567891012345678910") diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Cast.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Cast.Tests.fs index 2dfaa57b..378253f4 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Cast.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Cast.Tests.fs @@ -17,8 +17,8 @@ open FSharp.Control /// Asserts that a sequence contains the char values 'A'..'J'. let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "12345678910") diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Collect.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Collect.Tests.fs index fd3d7676..ba975595 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Collect.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Collect.Tests.fs @@ -102,8 +102,8 @@ module Immutable = let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "ABBCCDDEEFFGGHHIIJJK") diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Concat.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Concat.Tests.fs index df4c07e8..cfbd9464 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Concat.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Concat.Tests.fs @@ -15,8 +15,8 @@ open System.Collections.Generic let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "123456789101234567891012345678910") diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Delay.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Delay.Tests.fs index 20026528..a13c9111 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Delay.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Delay.Tests.fs @@ -15,8 +15,8 @@ open System.Collections.Generic let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "12345678910") diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Empty.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Empty.Tests.fs index a9477eb1..ccdba831 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Empty.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Empty.Tests.fs @@ -10,7 +10,7 @@ open FSharp.Control [] let ``TaskSeq-empty returns an empty sequence`` () = task { - let! sq = TaskSeq.empty |> TaskSeq.toSeqCachedAsync + let! sq = TaskSeq.empty |> TaskSeq.toListAsync Seq.isEmpty sq |> should be True Seq.length sq |> should equal 0 } diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Map.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Map.Tests.fs index c9a1ab1b..4793684e 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Map.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Map.Tests.fs @@ -16,8 +16,8 @@ open FSharp.Control /// Asserts that a sequence contains the char values 'A'..'J'. let validateSequence ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal "ABCDEFGHIJ") @@ -29,8 +29,8 @@ let validateSequenceWithOffset offset ts = |> String.concat "" ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.map string) + |> TaskSeq.toListAsync + |> Task.map (List.map string) |> Task.map (String.concat "") |> Task.map (should equal expected) diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.ToXXX.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.ToXXX.Tests.fs index 42656317..fbb5635b 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.ToXXX.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.ToXXX.Tests.fs @@ -35,13 +35,6 @@ module EmptySeq = results |> should be Empty } - [)>] - let ``TaskSeq-toSeqCachedAsync with empty`` variant = task { - let tq = Gen.getEmptyVariant variant - let! (results: seq<_>) = tq |> TaskSeq.toSeqCachedAsync - results |> Seq.toArray |> should be Empty - } - [)>] let ``TaskSeq-toIListAsync with empty`` variant = task { let tq = Gen.getEmptyVariant variant @@ -71,7 +64,7 @@ module EmptySeq = [)>] let ``TaskSeq-toSeqCached with empty`` variant = let tq = Gen.getEmptyVariant variant - let (results: seq<_>) = tq |> TaskSeq.toSeqCached + let (results: seq<_>) = tq |> TaskSeq.toSeq results |> Seq.toArray |> should be Empty module Immutable = @@ -90,13 +83,6 @@ module Immutable = results |> should equal [ 1..10 ] } - [)>] - let ``TaskSeq-toSeqCachedAsync should succeed`` variant = task { - let tq = Gen.getSeqImmutable variant - let! (results: seq<_>) = tq |> TaskSeq.toSeqCachedAsync - results |> Seq.toArray |> should equal [| 1..10 |] - } - [)>] let ``TaskSeq-toIListAsync should succeed`` variant = task { let tq = Gen.getSeqImmutable variant @@ -126,7 +112,7 @@ module Immutable = [)>] let ``TaskSeq-toSeqCached should succeed and be blocking`` variant = let tq = Gen.getSeqImmutable variant - let (results: seq<_>) = tq |> TaskSeq.toSeqCached + let (results: seq<_>) = tq |> TaskSeq.toSeq results |> Seq.toArray |> should equal [| 1..10 |] @@ -159,15 +145,6 @@ module SideEffects = results2 |> should equal [ 11..20 ] } - [)>] - let ``TaskSeq-toSeqCachedAsync should execute side effects multiple times`` variant = task { - let tq = Gen.getSeqWithSideEffect variant - let! (results1: seq<_>) = tq |> TaskSeq.toSeqCachedAsync - let! (results2: seq<_>) = tq |> TaskSeq.toSeqCachedAsync - results1 |> Seq.toArray |> should equal [| 1..10 |] - results2 |> Seq.toArray |> should equal [| 11..20 |] - } - [)>] let ``TaskSeq-toIListAsync should execute side effects multiple times`` variant = task { let tq = Gen.getSeqWithSideEffect variant @@ -205,7 +182,7 @@ module SideEffects = [)>] let ``TaskSeq-toSeqCached should execute side effects multiple times`` variant = let tq = Gen.getSeqWithSideEffect variant - let (results1: seq<_>) = tq |> TaskSeq.toSeqCached - let (results2: seq<_>) = tq |> TaskSeq.toSeqCached + let (results1: seq<_>) = tq |> TaskSeq.toSeq + let (results2: seq<_>) = tq |> TaskSeq.toSeq results1 |> Seq.toArray |> should equal [| 1..10 |] results2 |> Seq.toArray |> should equal [| 11..20 |] diff --git a/src/FSharp.Control.TaskSeq.Test/TestUtils.fs b/src/FSharp.Control.TaskSeq.Test/TestUtils.fs index ef50dba8..91baf383 100644 --- a/src/FSharp.Control.TaskSeq.Test/TestUtils.fs +++ b/src/FSharp.Control.TaskSeq.Test/TestUtils.fs @@ -138,8 +138,8 @@ type DummyTaskFactory(µsecMin: int64<µs>, µsecMax: int64<µs>) = module TestUtils = let verifyEmpty ts = ts - |> TaskSeq.toSeqCachedAsync - |> Task.map (Seq.isEmpty >> should be True) + |> TaskSeq.toArrayAsync + |> Task.map (Array.isEmpty >> should be True) /// Delays (no spin-wait!) between 20 and 70ms, assuming a 15.6ms resolution clock let longDelay () = task { do! Task.Delay(Random().Next(20, 70)) } diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj index 71d448a4..b0b89c51 100644 --- a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj +++ b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj @@ -8,9 +8,11 @@ Computation expression 'taskSeq' for processing IAsyncEnumerable sequences and module functions $(Version) Abel Braaksma; Don Syme - Provides the 'taskSeq' computation expression to support performance and statially optimized async sequences using the new F# 6.0 resumable state machines, similar to 'task'. + This library brings C#'s concept of 'await foreach' to F#. -This library brings C#'s concept of 'await foreach' to F#. +The 'taskSeq' computation expression adds support for awaitable asyncronous sequences with a similar ease of use and performance as F#'s 'task' CE. TaskSeq brings 'seq' and 'task' together in a safe way. + +Generates optimized IL code and comes with a comprehensive set of module functions. See README for more info. Copyright 2022 https://github.com/fsprojects/FSharp.Control.TaskSeq https://github.com/fsprojects/FSharp.Control.TaskSeq @@ -20,20 +22,39 @@ This library brings C#'s concept of 'await foreach' to F#. False nuget-package-readme.md - v.0.2 - - moved from NET 6.0, to NetStandard 2.1 for greater compatibility, no functional changes - - move to minimally necessary FSharp.Core version: 6.0.2 - - updated readme with progress overview, corrected meta info, added release notes - v.0.1.1 - - updated meta info in nuget package and added readme - v.0.1 + Release notes: + 0.2.2 + - removes TaskSeq.toSeqCachedAsync, which was incorrectly named. Use toSeq or toListAsync instead. + - renames TaskSeq.toSeqCached to TaskSeq.toSeq, which was its actual operational behavior. + 0.2.1 + - fixes an issue with ValueTask on completed iterations. + - adds `TaskSeq.except` and `TaskSeq.exceptOfSeq` async set operations. + 0.2 + - moved from NET 6.0, to NetStandard 2.1 for greater compatibility, no functional changes. + - move to minimally necessary FSharp.Core version: 6.0.2. + - updated readme with progress overview, corrected meta info, added release notes. + 0.1.1 + - updated meta info in nuget package and added readme. + 0.1 - initial release + - implements taskSeq CE using resumable state machines + - with support for: yield, yield!, let, let!, while, for, try-with, try-finally, use, use! + - and: tasks and valuetasks + - adds toXXX / ofXXX functions + - adds map/mapi/fold/iter/iteri/collect etc with async variants + - adds find/pick/choose/filter etc with async variants and 'try' variants + - adds cast/concat/append/prepend/delay/exactlyOne + - adds empty/isEmpty + - adds findIndex/indexed/init/initInfinite + - adds head/last/tryHead/tryLast/tail/tryTail + - adds zip/length + - + True \ diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fs b/src/FSharp.Control.TaskSeq/TaskSeq.fs index 9fb7e314..b94fbb26 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeq.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeq.fs @@ -46,7 +46,7 @@ module TaskSeq = e.DisposeAsync().AsTask().Wait() |] - let toSeqCached (source: taskSeq<'T>) = seq { + let toSeq (source: taskSeq<'T>) = seq { let e = source.GetAsyncEnumerator(CancellationToken()) try @@ -66,8 +66,6 @@ module TaskSeq = let toIListAsync source = Internal.toResizeArrayAndMapAsync (fun x -> x :> IList<_>) source - let toSeqCachedAsync source = Internal.toResizeArrayAndMapAsync (fun x -> x :> seq<_>) source - // // Convert 'OfXXX' functions // diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fsi b/src/FSharp.Control.TaskSeq/TaskSeq.fsi index dcbab450..aeae538d 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeq.fsi +++ b/src/FSharp.Control.TaskSeq/TaskSeq.fsi @@ -154,8 +154,16 @@ module TaskSeq = /// Returns taskSeq as an array. This function is blocking until the sequence is exhausted and will properly dispose of the resources. val toArray: source: taskSeq<'T> -> 'T[] - /// Returns taskSeq as a seq, similar to Seq.cached. This function is blocking until the sequence is exhausted and will properly dispose of the resources. - val toSeqCached: source: taskSeq<'T> -> seq<'T> + /// + /// Returns the task sequence as an F# , that is, an + /// . This function is blocking at each , but otherwise + /// acts as a normal delay-executed sequence. + /// It will then dispose of the resources. + /// + /// + /// The input task sequence. + /// The resulting task sequence. + val toSeq: source: taskSeq<'T> -> seq<'T> /// Unwraps the taskSeq as a Task>. This function is non-blocking. val toArrayAsync: source: taskSeq<'T> -> Task<'T[]> @@ -169,10 +177,6 @@ module TaskSeq = /// Unwraps the taskSeq as a Task>. This function is non-blocking. val toIListAsync: source: taskSeq<'T> -> Task> - /// Unwraps the taskSeq as a Task>. This function is non-blocking, - /// exhausts the sequence and caches the results of the tasks in the sequence. - val toSeqCachedAsync: source: taskSeq<'T> -> Task> - /// Create a taskSeq of an array. val ofArray: source: 'T[] -> taskSeq<'T> From 886743118c68714a5fd215c014b5f5a7692ff80a Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Thu, 10 Nov 2022 04:18:25 +0100 Subject: [PATCH 2/2] Release version 0.2.2 --- Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version.props b/Version.props index 94eb20c3..7f8337f7 100644 --- a/Version.props +++ b/Version.props @@ -1,5 +1,5 @@ - 0.2 + 0.2.2 \ No newline at end of file