我对F#非常陌生,目前正在阅读《F# for Fun and Profit》。在“为什么使用F#?”系列文章中,有一篇关于异步代码的文章。我遇到了
示例:
我的问题是为什么
为什么要有这种返回类型/行为?我习惯于使用 C#,在其中调用
编辑以澄清:
这样做的好处是什么:
与
Async.StartChild
函数,但不明白为什么返回值是这样的。示例:
let sleepWorkflow = async {
printfn "Starting sleep workflow at %O" DateTime.Now.TimeOfDay
do! Async.Sleep 2000
printfn "Finished sleep workflow at %O" DateTime.Now.TimeOfDay
}
let nestedWorkflow = async {
printfn "Starting parent"
let! childWorkflow = Async.StartChild sleepWorkflow
// give the child a chance and then keep working
do! Async.Sleep 100
printfn "Doing something useful while waiting "
// block on the child
let! result = childWorkflow
// done
printfn "Finished parent"
}
我的问题是为什么
Async.StartChild
不应该只返回 Async<'T>
而不是 Async<Async<'T>>
?你必须在它上面使用两次 let!
。即使文档也说明了:
在某些测试中,添加了一些休眠调用,似乎没有初始的此方法通常应作为 F# 异步工作流中 let! 绑定的直接右侧使用[...]在这种情况下,每次使用 StartChild 都会启动 childComputation 的实例,并返回一个表示等待完成操作的计算器对象。执行时,该计算器等待 childComputation 完成。
let!
,子计算就永远不会开始。为什么要有这种返回类型/行为?我习惯于使用 C#,在其中调用
async
方法将总是立即启动任务,即使您不 await
它。实际上,在 C# 中,如果 async
方法没有调用任何异步代码,它将同步运行。编辑以澄清:
这样做的好处是什么:
let! waiter = Async.StartChild otherComp // Start computation
// ...
let! result = waiter // Block
与
Async.StartChild
返回一个 Async<'T>
相比:let waiter = Async.StartChild otherComp // Start computation
// ...
let !result = waiter // Block
let!
是一个单子绑定,就像Haskell中的<-
一样,所以它必须返回该单子包装值的上下文,但在这种情况下,该值本身是一个Async<'T>
,所以我们需要我们所需的返回值。对吗? - AdamAsync<'T>
类型中隐藏的取消令牌。计算/异步工作流的实现方式将该令牌传递到使用!
的部分(是的,这些大多数被翻译为绑定) - 因此,这不完全是因为返回类型,而是因为您希望发生 令牌传递 - 如果您想在 C# 中实现这一点,则必须自己传递令牌(据我所知)。 - Random DevBind
隐藏了实现方式,就像 Haskell 的>>=
(也是绑定)运算符隐藏了额外的数据一样。原始的Async<'T>
处于一个上下文中。 - Adam