![]() |
VOOZH | about |
dotnet add package TaskBuilder.fs --version 2.1.0
NuGet\Install-Package TaskBuilder.fs -Version 2.1.0
<PackageReference Include="TaskBuilder.fs" Version="2.1.0" />
<PackageVersion Include="TaskBuilder.fs" Version="2.1.0" />Directory.Packages.props
<PackageReference Include="TaskBuilder.fs" />Project file
paket add TaskBuilder.fs --version 2.1.0
#r "nuget: TaskBuilder.fs, 2.1.0"
#:package TaskBuilder.fs@2.1.0
#addin nuget:?package=TaskBuilder.fs&version=2.1.0Install as a Cake Addin
#tool nuget:?package=TaskBuilder.fs&version=2.1.0Install as a Cake Tool
This is a single-file project that implements a
computation expression
for writing Tasks in F#.
It is free and unencumbered software released into the public domain.
F# comes with its own Async type and functions to convert back and
forth between Async and Task, but this is a bit of a hassle --
especially since now that Task has language-level support in C# and
VB.NET, it's the de facto standard for asynchrony on .NET.
Additionally, F#'s Async behaves a little differently from Task,
which can be confusing if you're used to the latter.
The goal of this computation expression builder is to let you write
asynchronous blocks that behave just like async methods in C# do.
For example, this F# method:
open System
open System.IO
open System.Linq
open FSharp.Control.Tasks.V2
type X() =
static member WriteFile() =
task {
do! Console.Out.WriteLineAsync("Enter a filename:")
let! name = Console.In.ReadLineAsync()
use file = File.CreateText(name)
for i in Enumerable.Range(0, 100) do
do! file.WriteLineAsync(String.Format("hello {0}", i))
do! Console.Out.WriteLineAsync("Done")
return name
}
Should work exactly the same as this C# method:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
class X
{
public static async Task<string> WriteFile()
{
await Console.Out.WriteLineAsync("Enter a filename:");
var name = await Console.In.ReadLineAsync();
using (var file = File.CreateText(name))
{
foreach (var i in Enumerable.Range(0, 100))
{
await file.WriteLineAsync(String.Format("hello {0}", i));
}
await Console.Out.WriteLineAsync("Done");
return name;
}
}
}
In practice there is a small performance hit compared to the C#
version, because the C# compiler compiles each async method to a
specialized state machine class, while TaskBuilder uses a
general-purpose state machine and must chain together continuation
functions to represent the computation. However, TaskBuilder should
still be faster than using Task.ContinueWith or Async.StartAsTask.
This is public domain code. I encourage you to simply copy TaskBuilder.fs into your own project and use it as you see fit. It is not necessary to credit me or include any legal notice with your copy of the code.
The other files are tests which you do not need to copy (but again, you are free to do so).
Note that by default, if you open FSharp.Control.Tasks.V2, you'll get
a task { ... } builder that behaves as closely to C#'s async methods as possible.
However, I have also included a version of the task { ... } builder under
FSharp.Control.Tasks.V2.ContextInsensitive which makes one minor change: it will
automatically call task.ConfigureAwait(false) on every task you await.
This can improve performance if you're writing library code or server-side code and don't need to interact with thread-unsafe things like Windows forms controls. If you're not sure whether you want to use this version of the builder, reading this MSDN article may help.
As of 7a04419, you should be able to bind anything "awaitable" with let!.
This basically means any type that has:
task.GetAwaiter()task.GetAwaiter().GetResult()task.GetAwaiter().IsCompletedWhen using FSharp.Control.Tasks.ContextInsensitive, you can also bind any type
that has a task.ConfigureAwait(false) returning an "awaitable" type.
In F# it is idiomatic to use tail recursion to implement loops more complex than a simple for or while.
This works with some computation expressions (like the built-in F# async
builder), but not with TaskBuilder.fs. As far as I know it is not possible to
make this work with TPL tasks. C# async/await function are not tail-call
optimized either, so at least this is consistent.
To implement a loop that may iterate many times (or indefinitely), use a while loop
instead of tail recursion.
For example:
let runPendingJobs() =
task {
let mutable anyPending = true
while anyPending do
let! jobToRun = checkForJob()
match jobToRun with
| None ->
anyPending <- false
| Some pendingJob ->
do! pendingJob()
}
let rec runPendingJobs() =
task {
let! jobToRun = checkForJob()
match jobToRun with
| None ->
return ()
| Some pendingJob ->
do! pendingJob()
return! runPendingJobs()
}
For a while, TaskBuilder.fs depended on a compiler behavior that was introduced in F# 4.1.
It wouldn't work with older compiler versions -- more accurately, it would work, but would be unpleasant to use because types would have to be explicitly annotated everywhere.
Thankfully, @gusty rewrote the builder classes and extension methods to work with all F# compiler versions.
But DLLs compiled using the old builder couldn't use the new builder code, since beneath the inline methods, there is a completely different set of classes and methods involved.
Therefore, the old code is still included for binary-compatibility, while the new code lives under the V2 namespace.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp1.0 netcoreapp1.0 was computed. netcoreapp1.1 netcoreapp1.1 was computed. netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard1.6 netstandard1.6 is compatible. netstandard2.0 netstandard2.0 was computed. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net45 net45 is compatible. net451 net451 was computed. net452 net452 was computed. net46 net46 is compatible. net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 is compatible. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen30 tizen30 was computed. tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on TaskBuilder.fs:
| Package | Downloads |
|---|---|
|
Chauffeur
Chauffeur is a tool for helping with delivering changes to an Umbraco instance. |
|
|
Chia
This library Chia contains utils for internal Danpower Reporting and is used by serveral reports. |
|
|
FSharp.Azure.Storage
A library that provides an idiomatic F# API for Microsoft Azure services. |
|
|
Chia.NetStandard
This library Chia contains utils for internal Danpower Reporting and is used by serveral reports. |
|
|
FSharp.Data.AgensGraph
A driver for the Postgresql fork Agensgraph |
Showing the top 6 popular GitHub repositories that depend on TaskBuilder.fs:
| Repository | Stars |
|---|---|
|
protobuf-net/protobuf-net.Grpc
GRPC bindings for protobuf-net and grpc-dotnet
|
|
|
Azure/azure-functions-durable-extension
Durable Task Framework extension for Azure Functions
|
|
|
Azure/azure-webjobs-sdk
Azure WebJobs SDK
|
|
|
torhovland/blazor-redux
Connecting a Redux state store with Blazor.
|
|
|
rebus-org/RebusSamples
Small sample projects
|
|
|
Tyrrrz/LtGt
Lightweight HTML processor
|