I just read about the new way to handle asynchronous functions in C# 5.0 using the await and async keywords. Examle from the C# reference on await:
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
A Task<byte[]> represents the Future of an asynchronous task that will generate a value of type byte[]. Using the keyword await on a Task will basically put the rest of the function in a continuation which will be called when the task is done. Any function that uses await must use the keyword async and have type Task<a> if it would return type a.
So the lines
byte[] urlContents = await getContentsTask;
// Do something with urlContents
would translate into something like
Task newTask = getContentsTask.registerContinuation(
byte[] urlContents => {
// Do something with urlContents
});
return newTask;
This feels a lot like a Monad (-transformer?). It feels like it should have some relation to the CPS monad, but maybe not.
Here is my attempt at writing corresponding Haskell types
-- The monad that async functions should run in
instance Monad Async
-- The same as the the C# keyword
await :: Async (Task a) -> Async a
-- Returns the current Task, should wrap what corresponds to
-- a async method in C#.
asyncFunction :: Async a -> Async (Task a)
-- Corresponds to the method Task.Run()
taskRun :: a -> Task a
and a rough translation of the above example
instance MonadIO Async -- Needed for this example
sumPageSizesAsync :: Async (Task ())
sumPageSizesAsync = asyncFunction $ do
client <- liftIO newHttpClient
-- client :: HttpClient
-- ...
getContentsTask <- getByteArrayAsync client url
-- getContentsTask :: Task [byte]
urlContents <- await getContentsTask
-- urlContents :: [byte]
-- ...
Would this be the corresponding types in Haskell? Is there any Haskell library this (or a similar way) implements way to handle asynchronous functions/actions?
Also: Could you build this using the CPS-transformer?
Edit
Yes, the Control.Concurrent.Async module does solve a similar problem (and has a similar interface), but does so in an entirely different way. I guess that Control.Monad.Task would be a closer match. What (I think) I am looking for is a monadic interface for Futures that uses Continuation Passing Style behind the scenes.
asyncit should provide what you are looking for: hackage.haskell.org/package/async - MoFuasyncpackage is even better than the C# feature, since it removes the responsibility over really being asynchronous from the function being called. The only disadvantage I can see is performance, sinceControl.Concurrent.Async(probably) requires a lot more bookkeeping than the simpler solution in C#. Lightweight threads and STM is very heavy compared to glorified callbacks. - Hjulle