How do I await an async method in F# - f#

How do I await an async method in F#?
I have the following code:
type LegoExample() =
let brick = Brick(BluetoothCommunication("COM3"))
let! result = brick.ConnectAsync();
Error:
Unexpected binder keyword in member definition
Note, I reviewed the following link:
However, I only observe the functional technique and not the OOP technique.

you get the error because the let! construct (just like the do!) needs to be placed inside a computational workflow (like async { ...} but there are others - it's basically the syntactic sugar F# gives you for monads - in C# it would be the from ... select ... stuff LINQ came with and in Haskell it would be do ... blocks)
so assuming brick.ConnectAsync() will return indeed some Async<...> then you can wait for it using Async.RunSynchronously like this:
let brick = Brick(BluetoothCommunication("COM3"))
let result = brick.ConnectAsync() |> RunSynchronously
sadly a quick browser search on the page you linked did not find ConnectAsync so I cannot tell you exactly what the indent of the snippet was here but most likely you wanted to have this inside a async { ... } block like this:
let myAsyncComputation =
async {
let brick = Brick(BluetoothCommunication "COM3")
let! result = brick.ConnectAsync()
// do something with result ...
}
(note that I remove some unnecessary parentheses etc.)
and then you could use this myAsyncComputation
inside yet another async { .. } workflow
with Async.RunSynchronously to run and await it
with Async.Start to run it in background (your block needs to have type Async<unit> for this
with Async.StartAsTask to start and get a Task<...> out of it
...

Related

Is there an alternative to "let!" to support function chaining?

Is there an alternative to "let!" to support function chaining?
I currently have this:
async {
let! result = token |> queryDay
result |> toTransactions
}
However, I would like to consolidate the above code into something like this:
async {
// NOTE: Async.Await isn't a thing
let result = token |> queryDay |> Async.Await |> toTransactions
}
Is there a way to achieve this?
From your examples I'm assuming that:
queryDay : 'a -> Async<'b>
toTransactions : 'b -> Async<'c>
Chaining monadic functions like that is called "bind". This is the core operation of a monad, the very essense of it. In fact the let! construct gets desugared into a call to async.Bind, and so does do!.
Unfortunately, the F# standard library doesn't offer a built-in standalone implementation of bind for Async. But there is one in FSharpx that you can use:
open FSharpx.Control
async {
let! result = token |> queryDay |> Async.bind toTransactions
}
Or if you don't want to use FSharpx, you can easily make one yourself by delegating to the computation builder:
module Async =
let bind f a = async.Bind(a, f)

Reader monad transformer sample with FSharpPlus

I'm trying to understand the reader monad transformer. I'm using FSharpPlus and try to compile the following sample which first reads something from the reader environment, then performs some async computation and finally combines both results:
open FSharpPlus
open FSharpPlus.Data
let sampleReader = monad {
let! value = ask
return value * 2
}
let sampleWorkflow = monad {
do! Async.Sleep 5000
return 4
}
let doWork = monad {
let! envValue = sampleReader
let! workValue = liftAsync sampleWorkflow
return envValue + workValue
}
ReaderT.run doWork 3 |> Async.RunSynchronously |> printfn "Result: %d"
With this I get a compilation error at the line where it says let! value = ask with the following totally unhelpful (at least for me) error message:
Type constraint mismatch when applying the default type 'obj' for a type inference variable. No overloads match for method 'op_GreaterGreaterEquals'.
Known return type: Async
Known type parameters: < obj , (int -> Async) >
It feels like I'm just missing some operator somewhere, but I can't figure it out.
Your code is correct, but F# type inference is not that smart in cases like this.
If you add a type annotation to sampleReader it will compile fine:
let sampleReader : ReaderT<int,Async<_>> = monad {
let! value = ask
return value * 2
}
// val sampleReader : FSharpPlus.Data.ReaderT<int,Async<int>> =
// ReaderT <fun:sampleReader#7>
Update:
After reading your comments.
If what you want is to make it generic, first of all your function has to be declared inline otherwise type constraints can't be applied:
let inline sampleReader = monad ...
But that takes you to the second problem: a constant can't be declared inline (actually there is a way but it's too complicated) only functions can.
So the easiest is to make it a function:
let inline sampleReader () = monad ...
And now the third problem the code doesn't compile :)
Here again, you can give type inference a minimal hint, just to say at the call site that you expect a ReaderT<_,_> will be enough:
let inline sampleReader () = monad {
let! value = ask
return value * 2
}
let sampleWorkflow = monad {
do! Async.Sleep 5000
return 4
}
let doWork = monad {
let! envValue = sampleReader () : ReaderT<_,_>
let! workValue = liftAsync sampleWorkflow
return envValue + workValue
}
ReaderT.run doWork 3 |> Async.RunSynchronously |> printfn "Result: %d"
Conclusion:
Defining a generic function is not that trivial task in F#.
If you look into the source of F#+ you'll see what I mean.
After running your example you'll see all the constraints being generated and you'll probably noted how the compile-time increased by making your function inline and generic.
These are all indications that we're pushing F# type system to the limits.
Although F#+ defines some ready-to-use generic functions, and these functions can sometimes be combined in such a way that you create your own generic functions, that's not the goal of the library, I mean you can but then you're on your own, in some scenarios like exploratory development it might make sense.

Return async value from Fable.Remoting

Here is a client side Fable.Remoting example that prints the result of an async function.
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
let server = Proxy.create<IServer>
async {
let! length = server.getLength “hello”
do printfn “%d” length // 5
}
|> Async.StartImmediate
How do I get the length value?
I see you've tagged your question with elmish, so I'm going to assume you have a Msg type defined. Don't use Async.StartImmediate or Async.RunSynchronously; in Elmish, you should use Cmd.OfAsync to schedule a message to be dispatched once the async block returns a value. There are four functions in Cmd.OfAsync (and the same four appear in Cmd.OfPromise as well): either, perform, attempt, and result. I'll break them down for you since their documentation isn't quite up to snuff yet:
either: takes four parameters, task, arg, ofSuccess, and ofError. task is the async function you want to call (of type 'a -> Async<'b>). arg is the parameter of type 'a that you want to pass to the task function. ofSuccess is a function of type 'b -> 'Msg: it will receive the result of the async function and is supposed to create a message, presumably one that incorporates the 'b result. Finally, ofError is a function of type exn -> 'Msg: if the task function throws an exception, then ofError will be called instead of ofSuccess, and is supposed to turn that exception into an Elmish message that your code can handle (presumably one that will log an error to the Javascript console or pop up a notification with Thoth.Toast or something like that).
perform: like either but there's no ofError parameter. Use this if your async command cannot fail (which is never the case with remote API calls, as it's always possible the network is down or your server is unresponsive), or if you just don't care about exceptions and don't mind an unhandled exception getting thrown.
attempt: like either but there's no ofSuccess parameter, so the task function's result will be ignored if it succeeds.
result: this one is completely different. It just takes a single parameter of type Async<'Msg>, i.e. you pass it an async block that is already going to produce a message.
With the code you've written, you would use Cmd.OfAsync.result if you wanted to make minimal changes to your code, but I would suggest using Cmd.OfAsync.perform instead (and upgrading it to Cmd.OfAsync.either once you have written some error-handling code). I'll show you both ways:
type Msg =
// ... rest of your messages go here
| GetLength of string
| LengthResult of int
let update msg model =
match msg with
// ... rest of your update function
| GetLength s ->
let usePerform = true
if usePerform then
model, Cmd.OfAsync.perform server.getLength s LengthResult
else
let length : Async<Msg> = async {
let! length = server.getLength s
return (LengthResult length)
}
model, Cmd.OfAsync.result length
| LengthResult len ->
// Do whatever you needed to do with the API result
printfn "Length was %d" len
model, Cmd.none
And if you were using either (which you really should do once you go to production), there would be a third message LogError of exn that would be handled like:
| LogError e ->
printfn "Error: %s" e.Message
model, Cmd.none
and the Cmd.OfAsync.perform line in the code above would become:
model, Cmd.OfAsync.either server.getLength s LengthResult LogError
That's the right way to handle async-producing functions in Elmish.
Async is one of the places where you use return in F#. So you need to return the length value. Also, Async.StartImmediate returns () (unit). Use something else, e.g. Async.RunSynchronously if you need the extracted value. Depends on what you need to achieve with it.
let length =
async {
let! length = async {return String.length "hello"}
do printfn "%d" length // 5
return length
} |> Async.RunSynchronously
length // val it : int = 5
Btw, you mention fable. So you might be able to use JS promise.
Some resources on Async in F#:
F# Async Guide from Jet
Async Programming
FSharp for Fun and Profit
Microsoft Docs
C# and F# Async
For those who want to call from js code.
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
open Fable.Core // required for Async.StartAsPromise
let server = Proxy.create<IServer>
let len_from_fable () =
async {
let! length = server.getLength “hello”
return length
} |> Async.StartAsPromise
call from js
async func() {
let len = await len_from_fable()
print(len)
}
works in fable 3.0.

Should parameterless async workflows in F# be wrapped in functions?

If I've got an async parameterless workflow in F#, is it necessary and/or idiomatic to make that a function, or is it best left as a raw value?
For example if I want to define getRemoteCounterAfterOneSec, polls some remote counter source, should it be
let getRemoteCounterAfterOneSec =
async {
do! Async.Sleep 1000
return! ...
}
or
let getRemoteCounterAfterOneSec () =
async {
do! Async.Sleep 1000
return! ...
}
It seems like they should do the same thing, just the latter has an unnecessary parameter. However I've seen this done both ways in various code. I've also seen places where the behavior ends up different: if using a MailboxProcessor and doing
let myFunc = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc
let! count2 = myFunc
}
then the mailboxProcessor is only called once; the second time it merely returns the same value calculated in the previous call. However if myFunc is a function then it calls mailboxProcessor twice as you'd expect.
let myFunc() = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc()
let! count2 = myFunc()
}
Is that a bug in the implementation? What's going on here and what is idiomatic?
When it comes to ordinary asyncs that you define yourself, then adding () has no effect (well, it means that the async that describes a computation is constructed repeatedly, but it has no practical effect).
I sometimes write it just to make my code easier to understand, or when the async is recursive (because then you get a warning when you have a recursive value). So, the following is fine, but it gives you a warning:
let rec loop =
async {
do! Async.Sleep 1000
if 1 > 2 then return 1
else return! loop }
The PostAndAsyncReply method is written a bit differently - and the name tries to reflect that. Normal F# async methods are named AsyncFooBar. This one has PostAndAsyncFooBar to indicate that it first posts and then asynchronously waits, that is something like:
let PostAndAsyncWait () =
post(message)
async { let! sth = wait ()
return sth }
So, here it actually posts outside of the async - this lets you call the function even if you are (syntactically) outside of an async block. And the name tries to be very explicit about this.
(But I would personally prefer if it was all inside async i.e. AsyncPostAndWait).

The most appropriate way to return a hot, awaited task from F# to a caller in C# framework

It looks like if the following situation occurs often and I wonder
What would be the most appropriate and shortest F# equivalent (e.g. no extra tasks created, has the same SynchronizationContext etc.)?
Does the following have something that should be fixed or improved?
Here DoAsync is a member function derived from a framework class, it takes a parameter and returns a hot, awaited task to the caller that is some framework function.
In C#:
public async Task DoAsync(int x)
{
if(x == 10)
{
await taskContext.ReturnAsync();
}
}
Here Async.Ignore is from here
In F#:
member x.DoAsync(int x) =
async {
if x = 10
return! Async.AwaitTask(taskContext.ReturnAsync() |> Async.Ignore)
else
return! Async.AwaitTask(Task.FromResult(0))
} |> Async.StartAsTask :> Task
Look at Tomas' answer for a simpler way. As an added note, in F# 4.0 it looks like there's an overload for non-generic Task available. More details at this Visual F# Tools PR.
Using Async.AwaitTask and Async.StartAsTask is the way to go. Although you do not really need to return anything from the async if you just want to return a non-generic Task:
member x.DoAsync(x:int) =
let work = async {
if x = 10 then
do! taskContext.ReturnAsync() |> Async.Ignore }
Async.StartAsTask(work) :> Task

Resources