哈斯克尔相当于C#5异步/的await [英] Haskell equivalent of C# 5 async/await

查看:152
本文介绍了哈斯克尔相当于C#5异步/的await的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚看了一下新的方式使用等待异步关键字来处理在C#5.0异步函数。 〔实施例从在 C#参考的await

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 任务&LT;字节[]&GT; 重新presents异步任务的未来,将产生类型的值字节[ ] 。使用关键字等待工作将基本上把函数的休息,这将被称为续当任务完成。任何使用功能等待必须使用关键字异步并键入任务&LT; A&GT; 是否会返回一个类型 A

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.

因此​​,行

byte[] urlContents = await getContentsTask;
// Do something with urlContents

将转化为类似

Task newTask = getContentsTask.registerContinuation(
               byte[] urlContents => {
                 // Do something with urlContents
               });
return newTask;


这感觉很像一个单子( - 变压器?)。这感觉就像它应该
有一些关系到CPS单子,但也许不是。


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]

    -- ...

这将是在Haskell相应的类型?是否有任何哈斯克尔库本(或类似方式)实现的方式来处理异步函数/动作?

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?

另外:你能建立这个使用CPS变压器

Also: Could you build this using the CPS-transformer?

是的, Control.Concurrent.Async < /一>模块确实解决类似的问题(和具有类似的接口),但在一个完全不同的方式这样做。我想这 Control.Monad.Task 将是一个更匹配。什么(我认为)我期待的是期货一元界面的使用延续传递风格幕后

推荐答案

下面是建立在异步工作单子C $ C>库:

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 Tasks 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)

运行叉TEST3 将酿出工作并返回未来,你可以随时调用要求的因此,如果必要则阻塞,直到完成。

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.

要表明它的作品,我会做两个简单的测试。首先,我将叉 TEST3 而不苛求其未来只是为了确保它正确派生复合螺纹:

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

这正常工作:

$ ./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
$

这篇关于哈斯克尔相当于C#5异步/的await的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆