How would I go about writing the following in F#?
var reader = await someDatabaseCommand.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var foo = reader.GetDouble(1);
// ...
}
I'm very new to F# so this is the best I can come up with
task {
let! reader = someDatabaseCommand.ExecuteReaderAsync ()
let! tmp1 = reader.ReadAsync ()
let mutable hasNext = tmp1
while hasNext do
// ...
let! tmp2 = reader.ReadAsync ()
hasNext <- tmp2
}
I know it's a C# library so it's not going to be perfect, but I'd like to avoid needing to store the result of ReadAsync in a variable, let alone have two temporaries. I don't know of a way to get the "result" of a Task without binding it to a name. Perhaps a recursive solution would work?
This library works very nicely with C#, because you can use await in the condition of the loop. I think that using recursive computation expression in F# is a bit nicer than the imperative solution (I do not think you can simplify that), but it is about the same length:
task {
let! reader = someDatabaseCommand.ExecuteReaderAsync ()
let rec loop () = task {
let! hasNext = reader.ReadAsync ()
if hasNext then
// ..
return! loop () }
return! loop ()
}
A more elaborate solution would be to use F# asynchronous sequences (from the FSharp.Control.AsyncSeq library). I think this only works for async (and so you'd have to use that instead of task), but it makes the code nicer. You can define a function that runs a command and returns an asynchronous sequence of results (for simplicity, I just return the reader, which is a bit dirty, but works):
#r "nuget: FSharp.Control.AsyncSeq"
#r "nuget: System.Data.SqlClient"
open FSharp.Control
let runCommand (cmd:System.Data.SqlClient.SqlCommand) = asyncSeq {
let! reader = cmd.ExecuteReaderAsync () |> Async.AwaitTask
let rec loop () = asyncSeq {
let! hasNext = reader.ReadAsync () |> Async.AwaitTask
if hasNext then
yield reader
yield! loop () }
yield! loop () }
Given this, you can very nicely iterate over the results using plain for loop inside async (using an overload added by the AsyncSeq library):
async {
for reader in runCommand someDatabaseCommand do
let foo = reader.GetDouble(1)
() }
Related
What is the idiomatic F# way of handling an asynchronous while loop accumulation?
I'm working with the new (still in preview) Azure Cosmos DB SDK. Querying the database returns a CosmosResultSetIterator<T> which has a HasMoreResults property and a FetchNextSetAsync() method. My straight-up translation of the C# code looks like this:
let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
let results = ResizeArray<'a>()
async {
while resultSetIterator.HasMoreResults do
let! response = resultSetIterator.FetchNextSetAsync() |> Async.AwaitTask
results.AddRange(response |> Seq.toArray)
return Seq.toList results
}
I would take a look at the AsyncSeq package. You can use it to create asynchronously computed sequences and then iterate them asynchronously or in parallel. This allows for the async-binding to be inside the sequence and the yield to occur asynchronously, so you don't have to build up an accumulator explicitly.
You can use it to do something like:
open FSharp.Control
let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
asyncSeq {
while resultSetIterator.HasMoreResults do
let! response = resultSetIterator.FetchNextSetAsync() |> Async.AwaitTask
yield! response |> AsyncSeq.ofSeq
}
IMHO tail-recursion is preferable to while loops as it's one way to avoid mutation.
For example:
let fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) =
let rec loop results =
async {
if resultSetIterator.HasMoreResults then
let! vs = resultSetIterator.FetchNextSetAsync () |> Async.AwaitTask
let vs = vs |> Seq.toList
return! loop (vs::results)
else
// List.rev needed because batches are in reverse
return results |> List.rev |> List.concat
}
loop []
Very recently, FSharp.Control.TaskSeq was added to support tasks natively with seqs. The answer here by #Just another metaprogrammer can be rewritten as
#r "nuget: FSharp.Control.TaskSeq"
open FSharp.Control
let private fetchItemsFromResultSet (resultSetIterator: CosmosResultSetIterator<'a>) = taskSeq {
while resultSetIterator.HasMoreResults do
let! response = resultSetIterator.FetchNextSetAsync()
yield! response |> TaskSeq.ofSeq
}
Assuming I have the following pseudo-C# code:
TResult MyMethod()
{
var firstTry = SomeExpensiveComputation1();
if (firstTry.IsSuccessful) return firstTry;
var secondTry = SomeExpensiveComputation2();
if (secondTry.IsPartiallySuccessful)
{
var subTry1 = SomeExpensiveComputationOn2_1(secondTry);
if (subTry1.IsSuccessful) return subTry1;
var subTry1 = SomeExpensiveComputationOn2_2(secondTry);
if (subTry1.IsSuccessful) return subTry1;
}
return LastExpensiveComputationThatNeverFails();
}
If I were to do this in F#, it'd look like this:
let MyMethod () =
let firstTry = SomeExpensiveComputation1 ()
if firstTry.IsSuccessful then firstTry else
let secondTry = SomeExpensiveComputation2 ()
if secondTry.IsSuccessful then
let subTry1 = SomeExpensiveComputationOn2_1 ()
if subTry1.IsSuccessful then subTry1 else
let subTry2 = SomeExpensiveComputationOn2_2 ()
if subTry2.IsSuccessful then subTry2 else LastExpensiveComputationThatNeverFails ()
else
LastExpensiveComputationThatNeverFails()
As you can see above, I had to repeat LastExpensiveComputationThatNeverFails twice. This doesn't have to be a method call, it can be many lines of inline computations (e.g. try to get some value from cache, if it doesn't exist calculate it.) One could refactor the code into another function, but I still don't like how the same code, even if it's just one line, has to be written twice (or more), as it leads to duplication and messy maintenance. What is the correct way to write such code in F#?
I think it's fine to make LastExpensiveComputationThatNeverFails a local function that is called whenever the result is needed.
However, one could also change the operations to return Option<_> and use the built-in combinator functions.
let MyMethod () =
SomeExpensiveComputation1 ()
|> Option.orElseWith
( fun () ->
SomeExpensiveComputation2 ()
|> Option.bind (fun _ -> SomeExpensiveComputationOn2_1 () |> Option.orElseWith SomeExpensiveComputationOn2_2)
)
|> Option.orElseWith LastExpensiveComputationThatNeverFails
Option.orElseWith LastExpensiveComputationThatNeverFails is only executed if the previous result is None which it will be upon failure.
How to do an simple await in F# ?
In C# I have code like this:
await collection.InsertOneAsync(DO);
var r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO)
So I created a let await = ... to my F# code become more similar with my C# code.
My current F# code is this:
let awaits (t: Threading.Tasks.Task) = t |> Async.AwaitTask |> Async.RunSynchronously
let await (t: Threading.Tasks.Task<'T>) = t |> Async.AwaitTask |> Async.RunSynchronously
let Busca (numero) =
let c = collection.Find(fun d -> d.Numero=numero).ToList()
c
let Insere(DO: DiarioOficial) =
//collection.InsertOneAsync(DO) |> Async.AwaitTask |> Async.RunSynchronously
collection.InsertOneAsync(DO) |> awaits
let Salva (DO: DiarioOficial) =
//let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> Async.AwaitTask |> Async.RunSynchronously
let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> await
r
I want to have only one definition for await (awaits), but the best I could do is this, because on Insere, type is Task, but on Salva, type is Task<'T>
If i use only the await, I get this compile error:
FS0001 The type 'Threading.Tasks.Task' is not compatible with the type 'Threading.Tasks.Task<'a>'
If I use only the awaits, it compiles, but I lose the return type from the async Task
I want to merge the await and awaits in a single
let await = ...
How can I do this?
In F# we tend to use another syntax. It is described e.g. here: https://fsharpforfunandprofit.com/posts/concurrency-async-and-parallel/.
or here: https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async
The idea of working with C# Tasks is to "convert" them to async with Async.Await<'T>
You can do it probably another way, but it is the most straightforward.
There are two parts of writing async code in both F# and C#.
You need to mark the method or code block as asynchronous. In C#, this is done using the async keyword. The F# equivalent is to use the async { ... } block (which is an expression, but otherwise, it is similar).
Inside async method or async { .. } block, you can make non-blocking calls. In C#, this is done using await and in F# it is done using let!. Note that this is not just a function call - the compiler handles this in a special way.
F# also uses Async<T> type rather than Task<T>, but those are easy to convert - e.g. using Async.AwaitTask. So, you probably want something like this:
let myAsyncFunction () = async {
let! _ = collection.InsertOneAsync(DO) |> Async.AwaitTask
let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO)
// More code goes here
}
I used let! to show the idea, but if you have an asynchronous operation that returns unit, you can also use do!
do! collection.InsertOneAsync(DO) |> Async.AwaitTask
I am trying to learn F# and am in the process of converting some C# code to F#.
I have the following C# method:
public async Task<Foo> GetFooAsync(byte[] content)
{
using (var stream = new MemoryStream(content))
{
return await bar.GetFooAsync(stream);
}
}
Where bar is some private field and GetFooAsync returns a Task<Foo>.
How does this translate to F#?
Here is what I currently have:
member public this.GetFooAsync (content : byte[]) =
use stream = new MemoryStream(content)
this.bar.GetFooAsync(stream)
Which returns a Task.
In F#, asynchrony is represented by the async computation builder, which is not an exact analog of Task, but can generally be used in place of one:
member public this.GetFooAsync (content : byte[]) =
async {
use stream = new MemoryStream(content)
return! this.bar.GetFooAsync(stream) |> Async.AwaitTask
}
|> Async.StartAsTask
If you are converting async/await-intensive C# code to F#, it might get cumbersome because of the difference between F#'s async and Task and the fact that you always have to call Async.AwaitTask
To avoid that you can use FSharpx library, which has a task computation expression.
let tplAsyncMethod p = Task.Run (fun _ -> string p)
// awaiting TPL method inside async computation expression
let asyncResult = async {
let! value1 = tplAsyncMethod 1 |> Async.AwaitTask
let! value2 = tplAsyncMethod 2 |> Async.AwaitTask
return value1 + value2
}
// The same logic using task computation expression
open FSharpx.Task
let taskResult = task {
let! value1 = tplAsyncMethod 1
let! value2 = tplAsyncMethod 2
return value1 + value2
}
The result of asyncResult is Async<string> and the result of taskResult is Task<string>.
This is the same as How do I await a response from an RX Subject without introducing a race condition?, but in F#.
The C# solution looks like:
static async void Foo()
{
var subject = new Subject<int>();
var firstInt = subject.FirstAsync().PublishLast();
firstInt.Connect();
subject.OnNext(42);
var x = await firstInt;
Console.WriteLine("Done waiting: " + x);
}
My attempt in F# is this:
let foo () =
async {
use subject = new Subject<int>()
let firstInt = subject.FirstAsync().PublishLast()
firstInt.Connect() |> ignore
subject.OnNext(42)
let! x = firstInt
printfn "Done waiting: %d" x
return ()
}
The let x! = firstInt gives the compile error This expression was expected to have type Async<'a> but here has type IConnectableObservable<int> so apparently C# does something under the hood that F# doesn't.
Is there a C# implicit interface cast at work here, that I need to do explicitly in F#? If so, I can't figure out what it is.
After further digging, it seems that C# calls GetAwaiter() under the hood when you await something. For a Subject or an IObservable, GetAwaiter returns an AsyncSubject, which isn't immediately useful in F#, but the ToTask extension method in System.Reactive.Threading.Tasks makes it useful. Apparently, you can apply ToTask directly to a Subject (or an IObservable) without going by way of GetAwaiter, so my problem is solved by changing the let! x ... statement to:
let! x = firstInt.ToTask() |> Async.AwaitTask
edit:
There's a better way
Using FSharpx.Async is a much better way of accomplishing the same thing:
open FSharpx.Control.Observable
let foo () =
async {
use subject = new Subject<int>()
subject.OnNext(42)
let! x = Async.AwaitObservable subject
printfn "Done waiting: %d" x
return ()
}