F#是否具有等同于OCaml的Async库的功能?具体来说,是否有能力轻松创建Deferred值并在填充后执行函数?

特别是,我要等到特定的引用发生更改,然后再执行某些操作。在OCaml中,我可以通过创建一个ivar并调用其read函数来实现。我该如何在F#中执行此操作?

最佳答案

简短答案

是的,我的Hopac库是Jane Street的Async库和F#的asynchronous workflows的近亲。 Hopac基于Concurrent ML(CML),并且可以说(从技术角度而不是观点而言)目前提供了比这两种方法更具表达性的编程模型。

更长的答案

简街的Async的Deferred与.Net的Task非常相似。两者本质上都是comonadic抽象,并在其顶部写有monadic层。

在Hopac中,相对于Deferred的最接近的实际上是Promise。但是,Hopac不会直接为Promises提供一元化层。当然,您可以轻松编写一个,但是我建议您坐一会儿。而是,Hopac提供了Job monad来对轻量级线程进行编码。这类似于how F#'s asynchronous workflows are defined,在我的主观意见中感觉更自然和easier to reason about

Jane Street的Async的Ivar是Hopac的IVar的近亲。两者都来自同一血统。

使CML和Hopac比Jane Street的Async和F#异步工作流更具表现力的是,可以使用同步事件(CML)或alternatives(Hopac)的组合器。使用这些多种并发协议(protocol)可以封装为一流的,可扩展的(高阶)选择性操作。

CML和Hopac的同步channels支持简单的集合点,这意味着在通信发生时,通信的两端是一致的。反过来,这又具有一些有趣的应用程序,例如实现Multicast channels的能力,该功能支持垃圾回收的发布-订阅样式的通信,而无需显式取消订阅(与Rx相反IObservable-IObserver)。

具体答案

这是一个F#交互式 session ,该 session 首先定义一个IVar,然后启动并发Job,该Job读取IVar的值并打印一条消息。最后,将IVar写入一个值:

> let nameVar : IVar<string> = ivar () ;;
val nameVar : IVar<string>
> start (nameVar |>> fun who -> printfn "Hello, %s!" who) ;;
val it : unit = ()
> run (nameVar <-= "Vesa") ;;
val it : unit = ()
> Hello, Vesa!

为了产生此输出,使用Hopac.fsx脚本启动了F#Interactive。

10-07 16:05