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.
Related
I am a little curious about the code example below and what people think.
The idea was to read from a NetworkStream (~20 msg/s) and instead of working in the main, pass things to MainboxProcessor to handle and get things back for bindings when done.
The usual way is to use PostAndReply, but I want to bind to ListView or other control in C#. Must do magic with LastN items and filtering anyway.
Plus, Rx has some error handling.
The example below observes numbers from 2..10 and returns "hello X". On 8 it stops like it was EOF. Made it to ToEnumerable because other thread finishes before otherwise, but it works with Subscribe as well.
What bothers me:
passing Subject(obj) around in recursion. I don't see any problems having around 3-4 of those. Good idea?
Lifetime of Subject.
open System
open System.Threading
open System.Reactive.Subjects
open System.Reactive.Linq // NuGet, take System.Reactive.Core also.
open System.Reactive.Concurrency
type SerializedLogger() =
let _letters = new Subject<string>()
// create the mailbox processor
let agent = MailboxProcessor.Start(fun inbox ->
// the message processing function
let rec messageLoop (letters:Subject<string>) = async{
// read a message
let! msg = inbox.Receive()
printfn "mailbox: %d in Thread: %d" msg Thread.CurrentThread.ManagedThreadId
do! Async.Sleep 100
// write it to the log
match msg with
| 8 -> letters.OnCompleted() // like EOF.
| x -> letters.OnNext(sprintf "hello %d" x)
// loop to top
return! messageLoop letters
}
// start the loop
messageLoop _letters
)
// public interface
member this.Log msg = agent.Post msg
member this.Getletters() = _letters.AsObservable()
/// Print line with prefix 1.
let myPrint1 x = printfn "onNext - %s, Thread: %d" x Thread.CurrentThread.ManagedThreadId
// Actions
let onNext = new Action<string>(myPrint1)
let onCompleted = new Action(fun _ -> printfn "Complete")
[<EntryPoint>]
let main argv =
async{
printfn "Main is on: %d" Thread.CurrentThread.ManagedThreadId
// test
let logger = SerializedLogger()
logger.Log 1 // ignored?
let xObs = logger
.Getletters() //.Where( fun x -> x <> "hello 5")
.SubscribeOn(Scheduler.CurrentThread)
.ObserveOn(Scheduler.CurrentThread)
.ToEnumerable() // this
//.Subscribe(onNext, onCompleted) // or with Dispose()
[2..10] |> Seq.iter (logger.Log)
xObs |> Seq.iter myPrint1
while true
do
printfn "waiting"
System.Threading.Thread.Sleep(1000)
return 0
} |> Async.RunSynchronously // return an integer exit code
I have done similar things, but using the plain F# Event type rather than Subject. It basically lets you create IObservable and trigger its subscribes - much like your use of more complex Subject. The event-based version would be:
type SerializedLogger() =
let letterProduced = new Event<string>()
let lettersEnded = new Event<unit>()
let agent = MailboxProcessor.Start(fun inbox ->
let rec messageLoop (letters:Subject<string>) = async {
// Some code omitted
match msg with
| 8 -> lettersEnded.Trigger()
| x -> letterProduced.Trigger(sprintf "hello %d" x)
// ...
member this.Log msg = agent.Post msg
member this.LetterProduced = letterProduced.Publish
member this.LettersEnded = lettersEnded.Publish
The important differences are:
Event cannot trigger OnCompleted, so I instead exposed two separate events. This is quite unfortunate! Given that Subject is very similar to events in all other aspects, this might be a good reason for using subject instead of plain event.
The nice aspect of using Event is that it is a standard F# type, so you do not need any external dependencies in the agent.
I noticed your comment noting that the first call to Log was ignored. That's because you subscribe to the event handler only after this call happens. I think you could use ReplaySubject variation on the Subject idea here - it replays all events when you subscribe to it, so the one that happened earlier would not be lost (but there is a cost to caching).
In summary, I think using Subject is probably a good idea - it is essentially the same pattern as using Event (which I think is quite standard way of exposing notifications from agents), but it lets you trigger OnCompleted. I would probably not use ReplaySubject, because of the caching cost - you just have to make sure to subscribe before triggering any events.
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
...
Suppose I have a stream which only allows one request/response at a time but is used in several threads.
Requests/commands should be throttled such that a new request can only occur once
the previous request has been sent and a reply has been received.
The user would be able to do this
let! res = getResponse("longResp")
let! res2 = getResponse("shortResp")
and not really know or care about the throttle.
I have tried with a modified version of Tomas Petricek's Throttling Agent that allows async with return values, but this requires the user to call getResponse("..") |> Enqueue |> w.Post which is a recipe for disaster (in case they forget to do so).
Is there a good/idiomatic way of doing this in F#?
Then make it explicit in your type system that the returned type needs to be unwrapped with another function. So instead of returning an Async<'T> which as you pointed out can be called directly with Async.Start, rather return something like:
type Queuable<'T> = Queuable of Async<'T>
Then getResponse changes to return a Queueable:
let getResponse (s:string) =
let r =
async{
do! write to your stream
return! read from your stream
}
Queuable r
Provide a function that unwraps the Queuable:
let enqueue (Queuable q) = async{
return! processor.PostAndAsyncReply(fun replyChannel -> replyChannel,q)
}
The processor is an agent that simply runs the Async workflow. Something like this:
let processor = new MailboxProcessor<_>(fun inbox ->
let rec Loop() = async {
let! (r:AsyncReplyChannel<_>,job) = inbox.Receive()
let! res = job
r.Reply res
return! Loop()}
Loop())
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).
define a function that has a single parameter of type string which which displayed on console. invoke the function passing it a message. ensure the function ignores any returned value
open System
let NoReturnFunction msg =
Console.WriteLine(string(msg))
NoReturnFunction "Hello World"
I am in a trouble to how to avoid return value of function
In this case there is no work to do because the WriteLine method doesn't return any values. It's a void returning function. In general though the way to ignore a return value in F# is to use the ignore function.
1 + 2 |> ignore
Couple of minor nit picks on the your code sample. The first is you can avoid the cast to string by simply typing the parameter. Second in F# it's more idiomatic to use the printfn function instead of Console.WriteLine
let NoReturnFunction (msg : string) =
printfn "%s" msg
For sake of completeness, you can also let F# infer the parameter type and the return type--like so:
let NoReturnFunction st = printfn "%s" st
This infers the type of s and the return type of NoReturnFunction (unit in this case).