我正在尝试通过几个示例来弄清楚 lwt 具体在做什么:
如果我有:
let%lwt x = f () in
let%lwt y = g () in
return ()
这是否运行 f 然后 g,或者由于 y 不依赖于 x,它会并行运行吗?
该特定示例按顺序运行,即f ()
直到解决返回的承诺之后才开始。g ()
g ()
f ()
看这个的方法是,当看
let%lwt x = e in
e'
意识到它e'
成为回调的主体,只有在x
可用时才会运行。因此,在问题的代码中,Lwt 首先看到:
(* Do this first. *)
let%lwt x = f () in
(* Do this once is available. *)
let%lwt y = g () in
return ()
并且,一旦x
可用,它就会留下
(* Do this next. *)
let%lwt y = g () in
(* Do this once y is available. *)
return ()
为了避免这种序列化,调用f ()
并且g ()
首先在没有任何干预let%lwt
的情况下将变量绑定到 Promise x'
,y'
这些函数返回并等待 Promise:
let x' = f () in
let y' = g () in
let%lwt x = x' in
let%lwt y = y' in
return ()
(回答标题,Lwt 不使用数据依赖关系。我不认为库可以访问这种数据依赖关系信息)。
在您的代码中,不,因为您使用Lwt.t
的是单子,而不是应用程序。
您可能已经熟悉异步 IO 以及函数Lwt.bind : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
和Lwt.return : 'a -> 'a Lwt.t
. 不过,以防万一,我将简要回顾一下:
Lwt.bind promise callback
awaits promise
,并在解决后,调用callback
结果,取回另一个承诺。Lwt.return data
创建一个解析为data
.'a t
monad 是具有一些功能bind : 'a t -> ('a -> 'b t) -> 'b t
和一些功能的泛型类型return : 'a -> 'a t
。(这些函数也必须遵循一定的规律,但我离题了。)显然,类型'a Lwt.t
与函数Lwt.bind
并Lwt.return
形成一个monad。
当人们想要表示某种“效果”或“计算”时,Monad 是一种常见的函数式编程模式,在这种情况下是异步 IO。Monad 很强大,因为该bind
函数允许以后的计算依赖于早期计算的结果。Ifm : 'a t
表示导致 的某些计算'a
,并且f : 'a -> 'b t
是一个使用 an'a
执行导致 a 的计算的函数'b
,则bind m f
makef
取决于 的结果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 相关的函数式编程模式是 applicative。应用程序是'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
,这意味着仅使用应用程序,以后的计算不能依赖于以前的计算。所有单子都是应用程序,但并非所有应用程序都是单子。
因为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,您可以直接编写翻译。