我正在尝试通过几个示例弄清lwt的具体作用:

如果我有:

let%lwt x = f () in
let%lwt y = g () in
return ()


它是先运行f然后运行g,还是因为y不依赖x,它将同时运行?

最佳答案

在您的代码中,没有,因为您将Lwt.t用作monad,而不是用作应用程序。

单音

您可能已经熟悉异步IO和功能Lwt.bind : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.tLwt.return : 'a -> 'a Lwt.t。为了以防万一,我将简要回顾一下:


Lwt.bind promise callback等待promise,并根据解决方案调用callback并返回结果,以重新获得另一个承诺。
Lwt.return data创建一个承诺,该承诺解析为data


monad是具有某些功能'a t和某些功能bind : 'a t -> ('a -> 'b t) -> 'b t的通用类型return : 'a -> 'a t。 (这些函数还必须遵守某些定律,但我偏离了题名。)显然,带有函数'a Lwt.tLwt.bind的类型Lwt.return构成一个monad。

当人们想要表示某种“效果”或“计算”(在这种情况下为异步IO)时,Monad是一种常见的功能编程模式。 Monad功能强大,因为bind函数使以后的计算取决于以前的结果。如果m : 'a t表示导致'a的某些计算,并且f : 'a -> 'b t是使用'a进行导致'b的计算的函数,则bind m f使f取决于m的结果。

对于Lwt.bind promise callbackcallback取决于promise的结果。在解析callback之前,promise中的代码无法运行。

当你写

let%lwt x = f () in
let%lwt y = g () in
return ()


您确实在写Lwt.bind (f ()) (fun x -> Lwt.bind (g ()) (fun y -> return ()))。因为g ()在回调内部,所以直到f ()解析后它才运行。

应用程式

与monad相关的功能编程模式是可应用的。应用程序是具有函数'a t,函数map : ('a -> 'b) -> 'a t -> 'b t和函数return : 'a -> 'a t的泛型类型both : 'a t * 'b t -> ('a * 'b) t。但是,与monad不同,应用程序不必具有bind : 'a t -> ('a -> 'b t) -> 'b t,这意味着仅使用应用程序时,以后的计算就不能依赖于先前的计算。所有monads都是appadatives,但并非所有appatives都是monads。

由于g ()不依赖于f ()的结果,因此可以将代码重写为使用both

let (let*) = bind
let (and*) = both

let* x = f ()
and* y = g () in
return ()


此代码转换为bind (fun (x, y) -> return ()) (both (f ()) (g ()))f ()g ()出现在bind的回调之外,这意味着它们将立即运行并可并行等待。 bothf ()g ()组合为一个承诺。

(let*)(and*)运算符是OCaml 4.08的新增功能。如果使用的是OCaml的早期版本,则可以直接编写翻译。


Lwt.both in the documentation
The Lwt home page contains a code snippit using let* and and*
"Binding operators" (let* and and*) in the OCaml manual

10-08 00:59