Skip to content

Commit 1fdcd4b

Browse files
Merge pull request #1078 from yawaramin/doc-lwt-ppx-sequence
Add back documentation on sequencing PPX
2 parents 2e8e968 + 02162dd commit 1fdcd4b

File tree

4 files changed

+143
-61
lines changed

4 files changed

+143
-61
lines changed

README.md

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[github-actions-img]: https://github.com/ocsigen/lwt/actions/workflows/workflow.yml/badge.svg?branch=master
99

1010
Lwt is a concurrent programming library for OCaml. It provides a single data
11-
type: the *promise*, which is a value that will become determined in the future.
11+
type: the *promise*, which is a value that will become resolved in the future.
1212
Creating a promise spawns a computation. When that computation is I/O, Lwt runs
1313
it in parallel with your OCaml code.
1414

@@ -20,9 +20,36 @@ Here is a simplistic Lwt program which requests the Google front page, and fails
2020
if the request is not completed in five seconds:
2121

2222
```ocaml
23-
open Lwt.Syntax
23+
let () =
24+
let request =
25+
let%lwt addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
26+
let google = Lwt_unix.((List.hd addresses).ai_addr) in
27+
28+
Lwt_io.(with_connection google (fun (incoming, outgoing) ->
29+
write outgoing "GET / HTTP/1.1\r\n";%lwt
30+
write outgoing "Connection: close\r\n\r\n";%lwt
31+
let%lwt response = read incoming in
32+
Lwt.return (Some response)))
33+
in
34+
35+
let timeout =
36+
Lwt_unix.sleep 5.;%lwt
37+
Lwt.return_none
38+
in
2439
40+
match Lwt_main.run (Lwt.pick [request; timeout]) with
41+
| Some response -> print_string response
42+
| None -> prerr_endline "Request timed out"; exit 1
43+
44+
(* ocamlfind opt -package lwt.unix,lwt_ppx -linkpkg example.ml && ./a.out *)
45+
```
46+
47+
If you are not using the `lwt_ppx` syntax extension, you can use the `let*`
48+
binding opoerators from the `Lwt.Syntax` module instead.
49+
50+
```ocaml
2551
let () =
52+
let open Lwt.Syntax in
2653
let request =
2754
let* addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
2855
let google = Lwt_unix.((List.hd addresses).ai_addr) in
@@ -36,24 +63,29 @@ let () =
3663
3764
let timeout =
3865
let* () = Lwt_unix.sleep 5. in
39-
Lwt.return None
66+
Lwt.return_none
4067
in
4168
4269
match Lwt_main.run (Lwt.pick [request; timeout]) with
4370
| Some response -> print_string response
4471
| None -> prerr_endline "Request timed out"; exit 1
4572
46-
(* ocamlfind opt -package lwt.unix -linkpkg example.ml && ./a.out *)
73+
(* ocamlfind opt -package lwt.unix,lwt_ppx -linkpkg example.ml && ./a.out *)
4774
```
4875

49-
In the program, functions such as `Lwt_io.write` create promises. The
50-
`let* ... in` construct is used to wait for a promise to become determined; the
51-
code after `in` is scheduled to run in a "callback." `Lwt.pick` races promises
52-
against each other, and behaves as the first one to complete. `Lwt_main.run`
53-
forces the whole promise-computation network to be executed. All the visible
54-
OCaml code is run in a single thread, but Lwt internally uses a combination of
55-
worker threads and non-blocking file descriptors to resolve in parallel the
56-
promises that do I/O.
76+
In the program above, functions such as `Lwt_io.write` create promises. The
77+
`let%lwt ... in` construct (provided by `lwt_ppx`) or the `let* ... in`
78+
construct (provided by `Lwt.Syntax`) are used to wait for a promise to resolve.
79+
The code after `in` is scheduled to run after the code inside the `let...in`
80+
has resolved.
81+
82+
`Lwt.pick` races promises against each other, and behaves as the first one to
83+
complete.
84+
85+
`Lwt_main.run` forces the whole promise-computation network to be executed. All
86+
the visible OCaml code is run in a single thread, but Lwt internally uses a
87+
combination of worker threads and non-blocking file descriptors to resolve in
88+
parallel the promises that do I/O.
5789

5890

5991
<br/>

src/core/index.mld

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
{1 Introduction}
44

55
Lwt is a concurrent programming library for OCaml. It provides a single data
6-
type: the {e promise}, which is a value that will become determined in the
7-
future. Creating a promise spawns a computation. When that computation is I/O,
8-
Lwt runs it in parallel with your OCaml code.
6+
type: the {e promise}, which is a value that will become resolved in the future.
7+
Creating a promise spawns a computation. When that computation is I/O, Lwt runs
8+
it in parallel with your OCaml code.
99

1010
OCaml code, including creating and waiting on promises, is run in a single
1111
thread by default, so you don't have to worry about locking or preemption. You
@@ -14,10 +14,37 @@ can detach code to be run in separate threads on an opt-in basis.
1414
Here is a simplistic Lwt program which requests the Google front page, and fails
1515
if the request is not completed in five seconds:
1616

17-
{[
18-
open Lwt.Syntax
17+
{@ocaml[
18+
let () =
19+
let request =
20+
let%lwt addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
21+
let google = Lwt_unix.((List.hd addresses).ai_addr) in
1922

23+
Lwt_io.(with_connection google (fun (incoming, outgoing) ->
24+
write outgoing "GET / HTTP/1.1\r\n";%lwt
25+
write outgoing "Connection: close\r\n\r\n";%lwt
26+
let%lwt response = read incoming in
27+
Lwt.return (Some response)))
28+
in
29+
30+
let timeout =
31+
Lwt_unix.sleep 5.;%lwt
32+
Lwt.return_none
33+
in
34+
35+
match Lwt_main.run (Lwt.pick [request; timeout]) with
36+
| Some response -> print_string response
37+
| None -> prerr_endline "Request timed out"; exit 1
38+
39+
(* ocamlfind opt -package lwt.unix,lwt_ppx -linkpkg example.ml && ./a.out *)
40+
]}
41+
42+
If you are not using the [lwt_ppx] syntax extension, you can use the [let*]
43+
binding opoerators from the [Lwt.Syntax] module instead.
44+
45+
{@ocaml[
2046
let () =
47+
let open Lwt.Syntax in
2148
let request =
2249
let* addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
2350
let google = Lwt_unix.((List.hd addresses).ai_addr) in
@@ -31,27 +58,30 @@ let () =
3158

3259
let timeout =
3360
let* () = Lwt_unix.sleep 5. in
34-
Lwt.return None
61+
Lwt.return_none
3562
in
3663

3764
match Lwt_main.run (Lwt.pick [request; timeout]) with
3865
| Some response -> print_string response
3966
| None -> prerr_endline "Request timed out"; exit 1
4067

41-
(* ocamlfind opt -package lwt.unix -linkpkg example.ml && ./a.out *)
68+
(* ocamlfind opt -package lwt.unix,lwt_ppx -linkpkg example.ml && ./a.out *)
4269
]}
4370

44-
In the program, functions such as [Lwt_io.write] create promises. The
45-
[let%lwt ... in] construct is used to wait for a promise to become determined;
46-
the code after [in] is scheduled to run in a "callback." [Lwt.pick] races
47-
promises against each other, and behaves as the first one to complete.
71+
In the program above, functions such as [Lwt_io.write] create promises. The
72+
[let%lwt ... in] construct (provided by [lwt_ppx]) or the [let* ... in]
73+
construct (provided by [Lwt.Syntax]) are used to wait for a promise to resolve.
74+
The code after [in] is scheduled to run after the code inside the [let...in]
75+
has resolved.
76+
77+
[Lwt.pick] races promises against each other, and behaves as the first one to
78+
complete.
79+
4880
[Lwt_main.run] forces the whole promise-computation network to be executed. All
4981
the visible OCaml code is run in a single thread, but Lwt internally uses a
5082
combination of worker threads and non-blocking file descriptors to resolve in
5183
parallel the promises that do I/O.
5284

53-
54-
5585
{1 Tour}
5686

5787
Lwt compiles to native code on Linux, macOS, Windows, and other systems. It's

src/core/lwt.mli

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
let () =
4646
Lwt_main.run begin
4747
let%lwt data = Lwt_io.(read_line stdin) in
48-
let%lwt () = Lwt_io.printl data in
48+
Lwt_io.printl data;%lwt
4949
Lwt.return ()
5050
end
5151
@@ -185,25 +185,26 @@ let () =
185185
{[
186186
let () =
187187
Lwt_main.run begin
188-
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3. in
189-
let five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
190-
let%lwt () = three_seconds in
191-
let%lwt () = Lwt_io.printl "3 seconds passed" in
192-
let%lwt () = five_seconds in
188+
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3.
189+
and five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
190+
191+
three_seconds;%lwt
192+
Lwt_io.printl "3 seconds passed";%lwt
193+
five_seconds;%lwt
193194
Lwt_io.printl "Only 2 more seconds passed"
194195
end
195196
196197
(* ocamlfind opt -linkpkg -thread -package lwt_ppx,lwt.unix code.ml && ./a.out *)
197198
]}
198199
199-
This program takes about five seconds to run. We are still new to [let%lwt],
200-
so let's desugar it:
200+
This program takes about five seconds to run. We are still new to [let%lwt]
201+
and [;%lwt], so let's desugar them:
201202
202203
{[
203204
let () =
204205
Lwt_main.run begin
205-
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3. in
206-
let five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
206+
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3.
207+
and five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
207208
208209
(* Both waits have already been started at this point! *)
209210
@@ -542,7 +543,7 @@ let () =
542543
let () =
543544
Lwt_main.run begin
544545
let%lwt line = Lwt_io.(read_line stdin) in
545-
let%lwt () = Lwt_unix.sleep 1. in
546+
Lwt_unix.sleep 1.;%lwt
546547
Lwt_io.printf "One second ago, you entered %s\n" line
547548
end
548549
@@ -834,8 +835,8 @@ val async : (unit -> unit t) -> unit
834835
{[
835836
let () =
836837
let rec show_nag () : _ Lwt.t =
837-
let%lwt () = Lwt_io.printl "Please enter a line" in
838-
let%lwt () = Lwt_unix.sleep 1. in
838+
Lwt_io.printl "Please enter a line";%lwt
839+
Lwt_unix.sleep 1.;%lwt
839840
show_nag ()
840841
in
841842
ignore (show_nag ()); (* Bad – see note for (1)! *)
@@ -860,8 +861,8 @@ let () =
860861
{[
861862
let () =
862863
let rec show_nag () : _ Lwt.t =
863-
let%lwt () = Lwt_io.printl "Please enter a line" in
864-
let%lwt () = Lwt_unix.sleep 1. in
864+
Lwt_io.printl "Please enter a line";%lwt
865+
Lwt_unix.sleep 1.;%lwt
865866
show_nag ()
866867
in
867868
Lwt.async (fun () -> show_nag ());
@@ -928,12 +929,12 @@ val both : 'a t -> 'b t -> ('a * 'b) t
928929
{[
929930
let () =
930931
let p_1 =
931-
let%lwt () = Lwt_unix.sleep 3. in
932+
Lwt_unix.sleep 3.;%lwt
932933
Lwt_io.printl "Three seconds elapsed"
933934
in
934935
935936
let p_2 =
936-
let%lwt () = Lwt_unix.sleep 5. in
937+
Lwt_unix.sleep 5.;%lwt
937938
Lwt_io.printl "Five seconds elapsed"
938939
in
939940
@@ -959,12 +960,12 @@ val join : (unit t) list -> unit t
959960
{[
960961
let () =
961962
let p_1 =
962-
let%lwt () = Lwt_unix.sleep 3. in
963+
Lwt_unix.sleep 3.;%lwt
963964
Lwt_io.printl "Three seconds elapsed"
964965
in
965966
966967
let p_2 =
967-
let%lwt () = Lwt_unix.sleep 5. in
968+
Lwt_unix.sleep 5.;%lwt
968969
Lwt_io.printl "Five seconds elapsed"
969970
in
970971
@@ -1120,7 +1121,7 @@ val cancel : _ t -> unit
11201121
{[
11211122
let () =
11221123
let p =
1123-
let%lwt () = Lwt_unix.sleep 5. in
1124+
Lwt_unix.sleep 5.;%lwt
11241125
Lwt_io.printl "Slept five seconds"
11251126
in
11261127
@@ -1842,21 +1843,19 @@ val pause : unit -> unit t
18421843
{[
18431844
let () =
18441845
let rec handle_io () =
1845-
let%lwt () = Lwt_io.printl "Handling I/O" in
1846-
let%lwt () = Lwt_unix.sleep 0.1 in
1846+
Lwt_io.printl "Handling I/O";%lwt
1847+
Lwt_unix.sleep 0.1;%lwt
18471848
handle_io ()
18481849
in
18491850
18501851
let rec compute n =
18511852
if n = 0 then
18521853
Lwt.return ()
18531854
else
1854-
let%lwt () =
1855-
if n mod 1_000_000 = 0 then
1856-
Lwt.pause ()
1857-
else
1858-
Lwt.return ()
1859-
in
1855+
(if n mod 1_000_000 = 0 then
1856+
Lwt.pause ()
1857+
else
1858+
Lwt.return ());%lwt
18601859
compute (n - 1)
18611860
in
18621861

0 commit comments

Comments
 (0)