Lwt.bind p_1 f
makes it so that f
will run when p_1
is fulfilled.
When p_1
is fulfilled with value v_1
, the callback f
is called with that same value v_1
. Eventually, after perhaps starting some I/O or other computation, f
returns promise p_2
.
Lwt.bind
itself returns immediately. It only attaches the callback f
to p_1
– it does not wait for p_2
. What Lwt.bind
returns is yet a third promise, p_3
. Roughly speaking, fulfillment of p_3
represents both p_1
and p_2
becoming fulfilled, one after the other.
A minimal example of this is an echo program:
let () =
let p_3 =
Lwt.bind
Lwt_io.(read_line stdin)
(fun line -> Lwt_io.printl line)
in
Lwt_main.run p_3
(* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
Rejection of p_1
and p_2
, and raising an exception in f
, are all forwarded to rejection of p_3
.
Precise behavior
Lwt.bind
returns a promise p_3
immediately. p_3
starts out pending, and is resolved as follows:
- The first condition to wait for is that
p_1
becomes resolved. It does not matter whether p_1
is already resolved when Lwt.bind
is called, or becomes resolved later – the rest of the behavior is the same. - If and when
p_1
becomes resolved, it will, by definition, be either fulfilled or rejected. - If
p_1
is rejected, p_3
is rejected with the same exception. - If
p_1
is fulfilled, with value v
, f
is applied to v
. f
may finish by returning the promise p_2
, or raising an exception.- If
f
raises an exception, p_3
is rejected with that exception. - Finally, the remaining case is when
f
returns p_2
. From that point on, p_3
is effectively made into a reference to p_2
. This means they have the same state, undergo the same state changes, and performing any operation on one is equivalent to performing it on the other.
Syntactic sugar
Lwt.bind
is almost never written directly, because sequences of Lwt.bind
result in growing indentation and many parentheses:
let () =
Lwt_main.run begin
Lwt.bind Lwt_io.(read_line stdin) (fun line ->
Lwt.bind (Lwt_unix.sleep 1.) (fun () ->
Lwt_io.printf "One second ago, you entered %s\n" line))
end
(* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
The recommended way to write Lwt.bind
is using the let%lwt
syntactic sugar:
let () =
Lwt_main.run begin
let%lwt line = Lwt_io.(read_line stdin) in
let%lwt () = Lwt_unix.sleep 1. in
Lwt_io.printf "One second ago, you entered %s\n" line
end
(* ocamlfind opt -linkpkg -thread -package lwt_ppx,lwt.unix code.ml && ./a.out *)
This uses the Lwt PPX (preprocessor). Note that we had to add package lwt_ppx
to the command line for building this program. We will do that throughout this manual.
Another way to write Lwt.bind
, that you may encounter while reading code, is with the >>=
operator:
open Lwt.Infix
let () =
Lwt_main.run begin
Lwt_io.(read_line stdin) >>= fun line ->
Lwt_unix.sleep 1. >>= fun () ->
Lwt_io.printf "One second ago, you entered %s\n" line
end
(* ocamlfind opt -linkpkg -thread -package lwt.unix code.ml && ./a.out *)
The >>=
operator comes from the module Lwt.Infix
, which is why we opened it at the beginning of the program.
See also Lwt.map
.