我正在尝试通过几个示例弄清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.t
和Lwt.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.t
和Lwt.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 callback
,callback
取决于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
的回调之外,这意味着它们将立即运行并可并行等待。 both
将f ()
和g ()
组合为一个承诺。(let*)
和(and*)
运算符是OCaml 4.08的新增功能。如果使用的是OCaml的早期版本,则可以直接编写翻译。Lwt.both
in the documentationThe Lwt home page contains a code snippit using
let*
and and*
"Binding operators" (
let*
and and*
) in the OCaml manual