Haskell equivalent of C# 5 async/await

asynchronous, c#, haskell

Solution

Here's a `Task` monad that builds on top of the `async` library:

import Control.Concurrent.Async (async, wait)

newtype Task a = Task { fork :: IO (IO a) }

newTask :: IO a -> Task a
newTask io = Task $ do
    w <- async io
    return (wait w)

instance Monad Task where
    return a = Task $ return (return a)
    m >>= f  = newTask $ do
        aFut <- fork m
        a    <- aFut
        bFut <- fork (f a)
        bFut

Note that I haven't checked the monad laws for this, so it might not be correct.

This is how you would define primitive tasks that run in the background:

import Control.Concurrent (threadDelay)

test1 :: Task Int
test1 = newTask $ do
    threadDelay 1000000  -- Wait 1 second
    putStrLn "Hello,"
    return 1

test2 :: Task Int
test2 = newTask $ do
    threadDelay 1000000
    putStrLn " world!"
    return 2

Then you can combine `Task`s using `do` notation which creates a new deferred task ready to be run:

test3 :: Task Int
test3 = do
    n1 <- test1
    n2 <- test2
    return (n1 + n2)

Running `fork test3` will spawn the `Task` and return a future which you can invoke at any time to demand the result, blocking if necessary until done.

To show that it works, I'll do two simple tests. First, I'll fork `test3` without demanding its future just to make sure it spawns the composite thread correctly:

main = do
    fork test3
    getLine -- wait without demanding the future

This works correctly:

$ ./task
Hello,
 world!
<Enter>
$

Now we can test what happens when we demand the result:

main = do
    fut <- fork test3
    n   <- fut  -- block until 'test3' is done
    print n

... which also works:

$ ./task
Hello,
 world!
3
$

Problem

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.

Original source