diff --git a/README.md b/README.md
index 9cf9bcd..cac8cf2 100644
--- a/README.md
+++ b/README.md
@@ -6,12 +6,11 @@
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].
+* Latest stable version: [0.4.0 is on NuGet][nuget].
## Release notes
-See [release notes.txt](release-notes.txt) for the version history of `TaskSeq`. See [Status overview](#status--planning) for current status of the surface area of `TaskSeq`.
+See [Releases](https://github.com/fsprojects/FSharp.Control.TaskSeq/releases) for the an extensive version history of `TaskSeq`. See [Status overview](#status--planning) below for a progress report.
-----------------------------------------
diff --git a/backdate-tags.cmd b/backdate-tags.cmd
new file mode 100644
index 0000000..1444417
--- /dev/null
+++ b/backdate-tags.cmd
@@ -0,0 +1,60 @@
+@echo off
+
+REM Batch file to override the date and/or message of existing tag, or create a new
+REM tag that takes the same date/time of an existing commit.
+REM
+REM Usage:
+REM > backdate-tags.cmd v0.1.1 "New message"
+REM
+REM How it works:
+REM * checkout the commit at the moment of the tag
+REM * get the date/time of that commit and store in GIT_COMMITER_DATE env var
+REM * recreate the tag (it will now take the date of its commit)
+REM * push tags changes to remove (with --force)
+REM * return to HEAD
+REM
+REM PS:
+REM * these escape codes are for underlining the headers so they stand out between all GIT's output garbage
+REM * the back-dating trick is taken from here: https://stackoverflow.com/questions/21738647/change-date-of-git-tag-or-github-release-based-on-it
+
+ECHO.
+ECHO [4;97mList existing tags:[0m
+git tag -n
+
+ECHO.
+ECHO [4;97mCheckout to tag:[0m
+git checkout tags/%1
+
+REM Output the first string, containing the date of commit, and put it in a file
+REM then set the contents of that file to env var GIT_COMMITTER_DATE (which in turn is needed to enable back-dating)
+REM then delete the temp file
+ECHO.
+ECHO [4;97mRetrieve original commit date[0m
+
+git show --format=%%aD | findstr "^[MTWFS][a-z][a-z],.*" > _date.tmp
+< _date.tmp (set /p GIT_COMMITTER_DATE=)
+del _date.tmp
+
+ECHO Committer date for tag: %GIT_COMMITTER_DATE%
+ECHO Overriding tag '%1' with text: %2
+ECHO.
+REM Override (with -af) the tag, if it exists (no quotes around %2)
+git tag -af %1 -m %2
+
+ECHO.
+ECHO [4;97mUpdated tag:[0m
+git tag --points-at HEAD -n
+ECHO.
+
+REM Push to remove and override (with --force)
+ECHO [4;97mPush changes to remote[0m
+git push --tags --force
+
+REM Go back to original HEAD
+ECHO.
+ECHO [4;97mBack to original HEAD[0m
+git checkout -
+
+ECHO.
+ECHO [4;97mList of all tags[0m
+git tag -n
diff --git a/release-notes.txt b/release-notes.txt
index df20d85..7f0d630 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.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj
index 53be692..83587f7 100644
--- a/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj
+++ b/src/FSharp.Control.TaskSeq.SmokeTests/FSharp.Control.TaskSeq.SmokeTests.fsproj
@@ -16,18 +16,23 @@
-
-
-
-
+
+
+
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
index d625d93..dbf1cfc 100644
--- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
+++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
@@ -60,16 +60,20 @@
-
+
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
index 297af81..9e6b6d9 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
@@ -57,7 +57,15 @@ Generates optimized IL code through resumable state machines, and comes with a c
-
-
+
+
+
+ true
+
diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fsi b/src/FSharp.Control.TaskSeq/TaskSeq.fsi
index cb5eefe..ff98586 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeq.fsi
+++ b/src/FSharp.Control.TaskSeq/TaskSeq.fsi
@@ -274,7 +274,7 @@ type TaskSeq =
static member append: source1: TaskSeq<'T> -> source2: TaskSeq<'T> -> TaskSeq<'T>
///
- /// Concatenates a task sequence with a non-async F# in
+ /// Concatenates a task sequence with a (non-async) F# in
/// and returns a single task sequence.
///
///
@@ -285,7 +285,7 @@ type TaskSeq =
static member appendSeq: source1: TaskSeq<'T> -> source2: seq<'T> -> TaskSeq<'T>
///
- /// Concatenates a non-async F# in with a task sequence in
+ /// Concatenates a (non-async) F# in with a task sequence in
/// and returns a single task sequence.
///
///
diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs
index 958678a..6ac6d0e 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs
+++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs
@@ -525,16 +525,16 @@ module LowPriority =
// and we need a way to distinguish these two methods.
//
// Types handled:
- // - ValueTask (non-generic, because it implements GetResult() -> unit)
+ // - (non-generic) ValueTask (because it implements GetResult() -> unit)
// - ValueTask<'T> (because it implements GetResult() -> 'TResult)
- // - Task (non-generic, because it implements GetResult() -> unit)
+ // - (non-generic) Task (because it implements GetResult() -> unit)
// - any other type that implements GetAwaiter()
//
// Not handled:
// - Task<'T> (because it only implements GetResult() -> unit, not GetResult() -> 'TResult)
[]
- member inline _.Bind< ^TaskLike, 'T, 'U, ^Awaiter, 'TOverall
+ member inline _.Bind< ^TaskLike, 'T, 'U, ^Awaiter
when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
and ^Awaiter :> ICriticalNotifyCompletion
and ^Awaiter: (member get_IsCompleted: unit -> bool)
diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi
index 4c185be..e060704 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi
+++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi
@@ -173,7 +173,7 @@ module LowPriority =
type TaskSeqBuilder with
[]
- member inline Bind< ^TaskLike, 'T, 'U, ^Awaiter, 'TOverall> :
+ member inline Bind< ^TaskLike, 'T, 'U, ^Awaiter> :
task: ^TaskLike * continuation: ('T -> ResumableTSC<'U>) -> ResumableTSC<'U>
when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
and ^Awaiter :> ICriticalNotifyCompletion
diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
index d7773ce..66a92f2 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
+++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
@@ -62,7 +62,21 @@ module internal TaskSeqInternal =
let inline raiseEmptySeq () = invalidArg "source" "The input task sequence was empty."
- let inline raiseCannotBeNegative name = invalidArg name "The value must be non-negative."
+ /// Moves the enumerator to its first element, assuming it has just been allocated.
+ /// Raises "The input sequence was empty" if there was no first element.
+ let inline moveFirstOrRaiseUnsafe (e: IAsyncEnumerator<_>) = task {
+ let! hasFirst = e.MoveNextAsync()
+
+ if not hasFirst then
+ invalidArg "source" "The input task sequence was empty."
+ }
+
+ /// Tests the given integer value and raises if it is -1 or lower.
+ let inline raiseCannotBeNegative name value =
+ if value >= 0 then
+ ()
+ else
+ invalidArg name $"The value must be non-negative, but was {value}."
let inline raiseOutOfBounds name =
invalidArg name "The value or index must be within the bounds of the task sequence."
@@ -183,10 +197,7 @@ module internal TaskSeqInternal =
task {
use e = source.GetAsyncEnumerator CancellationToken.None
- let! nonEmpty = e.MoveNextAsync()
-
- if not nonEmpty then
- raiseEmptySeq ()
+ do! moveFirstOrRaiseUnsafe e
let mutable acc = e.Current
@@ -202,10 +213,7 @@ module internal TaskSeqInternal =
task {
use e = source.GetAsyncEnumerator CancellationToken.None
- let! nonEmpty = e.MoveNextAsync()
-
- if not nonEmpty then
- raiseEmptySeq ()
+ do! moveFirstOrRaiseUnsafe e
let value = e.Current
let mutable accProjection = projection value
@@ -228,10 +236,7 @@ module internal TaskSeqInternal =
task {
use e = source.GetAsyncEnumerator CancellationToken.None
- let! nonEmpty = e.MoveNextAsync()
-
- if not nonEmpty then
- raiseEmptySeq ()
+ do! moveFirstOrRaiseUnsafe e
let value = e.Current
let! projValue = projectionAsync value
@@ -276,7 +281,10 @@ module internal TaskSeqInternal =
let count =
match count with
- | Some c -> if c >= 0 then c else raiseCannotBeNegative (nameof count)
+ | Some c ->
+ raiseCannotBeNegative (nameof count) c
+ c
+
| None -> Int32.MaxValue
match initializer with
@@ -741,9 +749,7 @@ module internal TaskSeqInternal =
let skipOrTake skipOrTake count (source: TaskSeq<_>) =
checkNonNull (nameof source) source
-
- if count < 0 then
- raiseCannotBeNegative (nameof count)
+ raiseCannotBeNegative (nameof count) count
match skipOrTake with
| Skip ->
@@ -907,8 +913,7 @@ module internal TaskSeqInternal =
/// InsertAt or InsertManyAt
let insertAt index valueOrValues (source: TaskSeq<_>) =
- if index < 0 then
- raiseCannotBeNegative (nameof index)
+ raiseCannotBeNegative (nameof index) index
taskSeq {
let mutable i = 0
@@ -933,8 +938,7 @@ module internal TaskSeqInternal =
}
let removeAt index (source: TaskSeq<'T>) =
- if index < 0 then
- raiseCannotBeNegative (nameof index)
+ raiseCannotBeNegative (nameof index) index
taskSeq {
let mutable i = 0
@@ -951,8 +955,7 @@ module internal TaskSeqInternal =
}
let removeManyAt index count (source: TaskSeq<'T>) =
- if index < 0 then
- raiseCannotBeNegative (nameof index)
+ raiseCannotBeNegative (nameof index) index
taskSeq {
let mutable i = 0
@@ -970,8 +973,7 @@ module internal TaskSeqInternal =
}
let updateAt index value (source: TaskSeq<'T>) =
- if index < 0 then
- raiseCannotBeNegative (nameof index)
+ raiseCannotBeNegative (nameof index) index
taskSeq {
let mutable i = 0
diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs
index c02bab3..ec076f2 100644
--- a/src/FSharp.Control.TaskSeq/Utils.fs
+++ b/src/FSharp.Control.TaskSeq/Utils.fs
@@ -1,22 +1,15 @@
namespace FSharp.Control
-open System.Threading.Tasks
open System
-open System.Diagnostics
-open System.Threading
+open System.Threading.Tasks
[]
module ValueTaskExtensions =
- /// Extensions for ValueTask that are not available in NetStandard 2.1, but are
- /// available in .NET 5+. We put them in Extension space to mimic the behavior of NetStandard 2.1
type ValueTask with
-
- /// (Extension member) Gets a task that has already completed successfully.
static member inline CompletedTask =
- // This mimics how it is done in .NET itself
+ // This mimics how it is done in net5.0 and later internally
Unchecked.defaultof
-
module ValueTask =
let False = ValueTask()
let True = ValueTask true
@@ -24,15 +17,15 @@ module ValueTask =
let inline ofSource taskSource version = ValueTask(taskSource, version)
let inline ofTask (task: Task<'T>) = ValueTask<'T> task
- let inline ignore (vtask: ValueTask<'T>) =
+ let inline ignore (valueTask: ValueTask<'T>) =
// this implementation follows Stephen Toub's advice, see:
// https://github.com/dotnet/runtime/issues/31503#issuecomment-554415966
- if vtask.IsCompletedSuccessfully then
+ if valueTask.IsCompletedSuccessfully then
// ensure any side effect executes
- vtask.Result |> ignore
+ valueTask.Result |> ignore
ValueTask()
else
- ValueTask(vtask.AsTask())
+ ValueTask(valueTask.AsTask())
[]
let inline FromResult (value: 'T) = ValueTask<'T> value
@@ -40,7 +33,6 @@ module ValueTask =
[]
let inline ofIValueTaskSource taskSource version = ofSource taskSource version
-
module Task =
let inline fromResult (value: 'U) : Task<'U> = Task.FromResult value
let inline ofAsync (async: Async<'T>) = task { return! async }
@@ -72,14 +64,12 @@ module Async =
let inline ofTask (task: Task<'T>) = Async.AwaitTask task
let inline ofUnitTask (task: Task) = Async.AwaitTask task
let inline toTask (async: Async<'T>) = task { return! async }
- let inline bind binder (task: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder task }
- let inline ignore (async': Async<'T>) = async {
- let! _ = async'
- return ()
- }
+ let inline ignore (async: Async<'T>) = Async.Ignore async
let inline map mapper (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async {
let! result = async
return mapper result
}
+
+ let inline bind binder (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder async }
diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi
index d34a1e5..b171720 100644
--- a/src/FSharp.Control.TaskSeq/Utils.fsi
+++ b/src/FSharp.Control.TaskSeq/Utils.fsi
@@ -6,10 +6,12 @@ open System.Threading.Tasks.Sources
[]
module ValueTaskExtensions =
- type System.Threading.Tasks.ValueTask with
- /// (Extension member) Gets a task that has already completed successfully.
- static member inline CompletedTask: System.Threading.Tasks.ValueTask
+ /// Shims back-filling .NET 5+ functionality for use on netstandard2.1
+ type ValueTask with
+
+ /// (Extension member) Gets a ValueTask that has already completed successfully.
+ static member inline CompletedTask: ValueTask
module ValueTask =
@@ -24,13 +26,13 @@ module ValueTask =
///
/// The function is deprecated since version 0.4.0,
- /// please use in its stead. See .
+ /// please use in its stead. See .
///
[]
val inline FromResult: value: 'T -> ValueTask<'T>
///
- /// Initialized a new instance of with an representing
+ /// Initializes a new instance of with an
/// representing its operation.
///
val inline ofSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask
@@ -42,21 +44,24 @@ module ValueTask =
[]
val inline ofIValueTaskSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask
- /// Creates a ValueTask form a Task<'T>
+ /// Creates a ValueTask from a Task<'T>
val inline ofTask: task: Task<'T> -> ValueTask<'T>
- /// Ignore a ValueTask<'T>, returns a non-generic ValueTask.
- val inline ignore: vtask: ValueTask<'T> -> ValueTask
+ /// Convert a ValueTask<'T> into a non-generic ValueTask, ignoring the result
+ val inline ignore: valueTask: ValueTask<'T> -> ValueTask
module Task =
- /// Convert an Async<'T> into a Task<'T>
+ /// Creates a Task<'U> that's completed successfully with the specified result.
+ val inline fromResult: value: 'U -> Task<'U>
+
+ /// Starts the `Async<'T>` computation, returning the associated `Task<'T>`
val inline ofAsync: async: Async<'T> -> Task<'T>
- /// Convert a unit-task into a Task
+ /// Convert a non-generic Task into a Task
val inline ofTask: task': Task -> Task
- /// Convert a non-task function into a task-returning function
+ /// Convert a plain function into a task-returning function
val inline apply: func: ('a -> 'b) -> ('a -> Task<'b>)
/// Convert a Task<'T> into an Async<'T>
@@ -66,8 +71,8 @@ module Task =
val inline toValueTask: task: Task<'T> -> ValueTask<'T>
///
- /// Convert a ValueTask<'T> to a Task<'T>. To use a non-generic ValueTask,
- /// consider using: .
+ /// Convert a ValueTask<'T> to a Task<'T>. For a non-generic ValueTask,
+ /// consider: .
///
val inline ofValueTask: valueTask: ValueTask<'T> -> Task<'T>
@@ -80,25 +85,22 @@ module Task =
/// Bind a Task<'T>
val inline bind: binder: ('T -> #Task<'U>) -> task: Task<'T> -> Task<'U>
- /// Create a task from a value
- val inline fromResult: value: 'U -> Task<'U>
-
module Async =
/// Convert an Task<'T> into an Async<'T>
val inline ofTask: task: Task<'T> -> Async<'T>
- /// Convert a unit-task into an Async
+ /// Convert a non-generic Task into an Async
val inline ofUnitTask: task: Task -> Async
- /// Convert a Task<'T> into an Async<'T>
+ /// Starts the `Async<'T>` computation, returning the associated `Task<'T>`
val inline toTask: async: Async<'T> -> Task<'T>
/// Convert an Async<'T> into an Async, ignoring the result
- val inline ignore: async': Async<'T> -> Async
+ val inline ignore: async: Async<'T> -> Async
/// Map an Async<'T>
val inline map: mapper: ('T -> 'U) -> async: Async<'T> -> Async<'U>
/// Bind an Async<'T>
- val inline bind: binder: (Async<'T> -> Async<'U>) -> task: Async<'T> -> Async<'U>
+ val inline bind: binder: (Async<'T> -> Async<'U>) -> async: Async<'T> -> Async<'U>