This question combines two topics I don't fully understand
Reading through a paper about async in F#, I came across the topic of Agents/MailboxProcessors, which can be used to implement reactive state machines. Could the new async/await functionality in C#5 be used to implement something similar in C#, or is there already something analogue that would be better suited?
With a bit of pretty horrible hacking, you can use the MailboxProcessor
type from C# using async
. Some difficulties are that the type uses some F# specific features (optional arguments are options, functions are FSharpFunc
type, etc.)
Technically, the biggest difference is that F# async is dealyed while C# async creates a task that is already running. This means that to construct F# async from C#, you need to write a method that takes unt -> Task<T>
and creates Async<T>
. I wrote a blog post that discusses the difference.
Anwyay, if you want to experiment, here is some code you can use:
static FSharpAsync<T> CreateAsync<T>(Func<Task<T>> f)
{
return FSharpAsync.FromContinuations<T>(
FuncConvert.ToFSharpFunc<
Tuple< FSharpFunc<T, Unit>,
FSharpFunc<Exception, Unit>,
FSharpFunc<OperationCanceledException, Unit> >>(conts => {
f().ContinueWith(task => {
try { conts.Item1.Invoke(task.Result); }
catch (Exception e) { conts.Item2.Invoke(e); }
});
}));
}
static void MailboxProcessor() {
var body = FuncConvert.ToFSharpFunc<
FSharpMailboxProcessor<int>,
FSharpAsync<Unit>>(mbox =>
CreateAsync<Unit>(async () => {
while (true) {
var msg = await FSharpAsync.StartAsTask
( mbox.Receive(FSharpOption<int>.None),
FSharpOption<TaskCreationOptions>.None,
FSharpOption<CancellationToken>.None );
Console.WriteLine(msg);
}
return null;
}));
var agent = FSharpMailboxProcessor<int>.Start(body,
FSharpOption<CancellationToken>.None);
agent.Post(1);
agent.Post(2);
agent.Post(3);
Console.ReadLine();
}
As you can see, this looks really horrible :-).
In principle, it could be possible to write a C# friendly wrapper for the MailboxProcessor
type (just extract the ugly bits from this code), but there are some problems.
In F# you often use tail-recursive asyncs to implement the state machine in the mailbox processor. If you write the same thing in C#, you'll eventually get StackOverflow
, so you'd need to write loops with mutable state.
It is perfectly possible to write the agent in F# and call it from C#. This is just a matter of exposing C#-friendly interface from F# (using the Async.StartAsTask
method).
In principle, I expect it would be straightforward to translate these F# APIs into C#-plus-async-await.
In practice, I am unclear if it would come out beautiful, or ugly and full of extra type annotations, or simply un-idiomatic and in need of some API-massaging to make it feel more at home in C#. I think the jury is out until someone does the work and tries it. (I presume there is no such sample in the await CTP.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With