F#-编写接受非通用和通用参数的函数

时间:2018-12-13 12:20:58

标签: f#

我这样定义了await函数:

let await (task : Task<'a>) =
    task |> Async.AwaitTask |> Async.RunSynchronously

和两个类似的任务:

let stringTask = new Task<string>(fun () -> "something")

let unitTask = new Task(fun () -> printf "something")

这样称呼他们:

let stringResult = await stringTask
await unitTask

但是第二个不是通用的,因此我无法调用await,因此我像下面这样编辑了函数参数:

let await (task : Task) =
    task |> Async.AwaitTask |> Async.RunSynchronously

问题是现在await stringTask返回unit而不是string

我应该如何编写await函数来接受Task <'a>和Task作为参数并等待它?

3 个答案:

答案 0 :(得分:5)

您对await的原始定义很好。

问题出在unitTask上,它不是通用的。以与stringTask相同的方式使其通用:

let unitTask = new Task<unit>(fun () -> printf "something")

如果要同时处理通用Task<'a>和非通用Task,则有2个选择。

创建2个await函数(以函数方式):

let await     (task : Task<'a>) = task |> Async.AwaitTask |> Async.RunSynchronously
let awaitUnit (task : Task    ) = task |> Async.AwaitTask |> Async.RunSynchronously

或创建2个Await成员,例如类型为Task(OO方法):

type Task with 
    static member Await (task : Task    ) = task |> Async.AwaitTask |> Async.RunSynchronously
    static member Await (task : Task<'a>) = task |> Async.AwaitTask |> Async.RunSynchronously

按惯例,成员使用Pascal大小写,因此我使用Await而不是await

在致电task.Start()之前,请记住先致电await

答案 1 :(得分:5)

curselection()已经对Async.AwaitTaskTask<'a>都进行了重载,因此除非您确实需要帮助函数,否则可以直接使用它:

Task

如果这是您的实际代码,并且确实需要阻止线程等待这些结果,则也可以直接使用Task API来保存Task->异步翻译开销:

let stringResult = Async.AwaitTask stringTask |> Async.RunSynchronously
Async.AwaitTask unitTask |> Async.RunSynchronously

答案 2 :(得分:1)

您可以创建一个Task -> Task<unit>辅助函数,以将从API中获得的Task个对象转换为Task<unit>。我怀疑这不是最好的方法,因为已经有一段时间了,因为我一直非常关注F#异步与框架基于任务的异步之间的区别,但这在您的琐碎扩展中起作用例如:

open System.Threading
open System.Threading.Tasks

let toUnitTask (t : Task) =
    new Task<_>(fun () -> t.Start(); t |> Async.AwaitTask |> Async.RunSynchronously)

let await (task : Task<_>) =
    task |> Async.AwaitTask |> Async.RunSynchronously

let stringTask = new Task<string>(fun () -> Thread.Sleep 3000; "something")
let unitTask = new Task(fun () -> Thread.Sleep 2000; printfn "something") |> toUnitTask

stringTask.Start()
unitTask.Start()

let stringResult = await stringTask
await unitTask