Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,38 @@ Here is a simplistic Lwt program which requests the Google front page, and fails
if the request is not completed in five seconds:

```ocaml
open Lwt.Syntax

let () =
let request =
let* addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
let%lwt addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
let google = Lwt_unix.((List.hd addresses).ai_addr) in

Lwt_io.(with_connection google (fun (incoming, outgoing) ->
let* () = write outgoing "GET / HTTP/1.1\r\n" in
let* () = write outgoing "Connection: close\r\n\r\n" in
let* response = read incoming in
write outgoing "GET / HTTP/1.1\r\n";%lwt
write outgoing "Connection: close\r\n\r\n";%lwt
let%lwt response = read incoming in
Lwt.return (Some response)))
in

let timeout =
let* () = Lwt_unix.sleep 5. in
Lwt.return None
Lwt_unix.sleep 5.;%lwt
Lwt.return_none
in

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

(* ocamlfind opt -package lwt.unix -linkpkg example.ml && ./a.out *)
(* ocamlfind opt -package lwt.unix,lwt_ppx -linkpkg example.ml && ./a.out *)
```

In the program, functions such as `Lwt_io.write` create promises. The
`let* ... in` construct is used to wait for a promise to become determined; the
code after `in` is scheduled to run in a "callback." `Lwt.pick` races promises
against each other, and behaves as the first one to complete. `Lwt_main.run`
forces the whole promise-computation network to be executed. All the visible
OCaml code is run in a single thread, but Lwt internally uses a combination of
worker threads and non-blocking file descriptors to resolve in parallel the
promises that do I/O.
`let%lwt ... in` construct is used to wait for a promise to become determined;
the code after `in` is scheduled to run in a "callback." `Lwt.pick` races
promises against each other, and behaves as the first one to complete.
`Lwt_main.run` forces the whole promise-computation network to be executed. All
the visible OCaml code is run in a single thread, but Lwt internally uses a
combination of worker threads and non-blocking file descriptors to resolve in
parallel the promises that do I/O.


<br/>
Expand Down
16 changes: 7 additions & 9 deletions src/core/index.mld
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,28 @@ Here is a simplistic Lwt program which requests the Google front page, and fails
if the request is not completed in five seconds:

{[
open Lwt.Syntax

let () =
let request =
let* addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
let%lwt addresses = Lwt_unix.getaddrinfo "google.com" "80" [] in
let google = Lwt_unix.((List.hd addresses).ai_addr) in

Lwt_io.(with_connection google (fun (incoming, outgoing) ->
let* () = write outgoing "GET / HTTP/1.1\r\n" in
let* () = write outgoing "Connection: close\r\n\r\n" in
let* response = read incoming in
write outgoing "GET / HTTP/1.1\r\n";%lwt
write outgoing "Connection: close\r\n\r\n";%lwt
let%lwt response = read incoming in
Lwt.return (Some response)))
in

let timeout =
let* () = Lwt_unix.sleep 5. in
Lwt.return None
Lwt_unix.sleep 5.;%lwt
Lwt.return_none
in

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

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

In the program, functions such as [Lwt_io.write] create promises. The
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that some of these examples actually were using the PPX originally, as you can see in the next line:

Expand Down
55 changes: 27 additions & 28 deletions src/core/lwt.mli
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
let () =
Lwt_main.run begin
let%lwt data = Lwt_io.(read_line stdin) in
let%lwt () = Lwt_io.printl data in
Lwt_io.printl data;%lwt
Lwt.return ()
end

Expand Down Expand Up @@ -185,25 +185,26 @@ let () =
{[
let () =
Lwt_main.run begin
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3. in
let five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
let%lwt () = three_seconds in
let%lwt () = Lwt_io.printl "3 seconds passed" in
let%lwt () = five_seconds in
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3.
and five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in

three_seconds;%lwt
Lwt_io.printl "3 seconds passed";%lwt
five_seconds;%lwt
Lwt_io.printl "Only 2 more seconds passed"
end

(* ocamlfind opt -linkpkg -thread -package lwt_ppx,lwt.unix code.ml && ./a.out *)
]}

This program takes about five seconds to run. We are still new to [let%lwt],
so let's desugar it:
This program takes about five seconds to run. We are still new to [let%lwt]
and [;%lwt], so let's desugar them:

{[
let () =
Lwt_main.run begin
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3. in
let five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in
let three_seconds : unit Lwt.t = Lwt_unix.sleep 3.
and five_seconds : unit Lwt.t = Lwt_unix.sleep 5. in

(* Both waits have already been started at this point! *)

Expand Down Expand Up @@ -542,7 +543,7 @@ let () =
let () =
Lwt_main.run begin
let%lwt line = Lwt_io.(read_line stdin) in
let%lwt () = Lwt_unix.sleep 1. in
Lwt_unix.sleep 1.;%lwt
Lwt_io.printf "One second ago, you entered %s\n" line
end

Expand Down Expand Up @@ -834,8 +835,8 @@ val async : (unit -> unit t) -> unit
{[
let () =
let rec show_nag () : _ Lwt.t =
let%lwt () = Lwt_io.printl "Please enter a line" in
let%lwt () = Lwt_unix.sleep 1. in
Lwt_io.printl "Please enter a line";%lwt
Lwt_unix.sleep 1.;%lwt
show_nag ()
in
ignore (show_nag ()); (* Bad – see note for (1)! *)
Expand All @@ -860,8 +861,8 @@ let () =
{[
let () =
let rec show_nag () : _ Lwt.t =
let%lwt () = Lwt_io.printl "Please enter a line" in
let%lwt () = Lwt_unix.sleep 1. in
Lwt_io.printl "Please enter a line";%lwt
Lwt_unix.sleep 1.;%lwt
show_nag ()
in
Lwt.async (fun () -> show_nag ());
Expand Down Expand Up @@ -928,12 +929,12 @@ val both : 'a t -> 'b t -> ('a * 'b) t
{[
let () =
let p_1 =
let%lwt () = Lwt_unix.sleep 3. in
Lwt_unix.sleep 3.;%lwt
Lwt_io.printl "Three seconds elapsed"
in

let p_2 =
let%lwt () = Lwt_unix.sleep 5. in
Lwt_unix.sleep 5.;%lwt
Lwt_io.printl "Five seconds elapsed"
in

Expand All @@ -959,12 +960,12 @@ val join : (unit t) list -> unit t
{[
let () =
let p_1 =
let%lwt () = Lwt_unix.sleep 3. in
Lwt_unix.sleep 3.;%lwt
Lwt_io.printl "Three seconds elapsed"
in

let p_2 =
let%lwt () = Lwt_unix.sleep 5. in
Lwt_unix.sleep 5.;%lwt
Lwt_io.printl "Five seconds elapsed"
in

Expand Down Expand Up @@ -1120,7 +1121,7 @@ val cancel : _ t -> unit
{[
let () =
let p =
let%lwt () = Lwt_unix.sleep 5. in
Lwt_unix.sleep 5.;%lwt
Lwt_io.printl "Slept five seconds"
in

Expand Down Expand Up @@ -1842,21 +1843,19 @@ val pause : unit -> unit t
{[
let () =
let rec handle_io () =
let%lwt () = Lwt_io.printl "Handling I/O" in
let%lwt () = Lwt_unix.sleep 0.1 in
Lwt_io.printl "Handling I/O";%lwt
Lwt_unix.sleep 0.1;%lwt
handle_io ()
in

let rec compute n =
if n = 0 then
Lwt.return ()
else
let%lwt () =
if n mod 1_000_000 = 0 then
Lwt.pause ()
else
Lwt.return ()
in
(if n mod 1_000_000 = 0 then
Lwt.pause ()
else
Lwt.return ());%lwt
compute (n - 1)
in

Expand Down
37 changes: 29 additions & 8 deletions src/ppx/ppx_lwt.mli
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

This extension adds the following syntax:

- lwt-binding:
{3 Lwt binding}

{[
let%lwt ch = get_char stdin in
Expand Down Expand Up @@ -51,7 +51,28 @@ code

Not using parentheses will confuse the OCaml parser.

- exception catching:
{3 Sequencing promises}

{[
<expr1>;%lwt
<expr2>
]}

For example:

{[
Lwt_io.printl "Hello,";%lwt
Lwt_io.printl "world!"
]}

is expanded to:

{[
bind (Lwt_io.printl "Hello,") (fun () ->
Lwt_io.printl "world!")
]}

{3 Exception handling}

{[
try%lwt
Expand Down Expand Up @@ -86,7 +107,7 @@ catch (fun () -> f x)
Note that the [exn -> Lwt.reraise exn] branch is automatically added
when needed.

- finalizer:
{3 Finalizer}

{[
(<expr>) [%finally <expr>]
Expand All @@ -95,13 +116,13 @@ catch (fun () -> f x)
You can use [[%lwt.finally ...]] instead of [[%finally ...]].


- assertion:
{3 Assertion}

{[
assert%lwt <expr>
]}

- for loop:
{3 For loop}

{[
for%lwt i = <expr> to <expr> do
Expand All @@ -117,15 +138,15 @@ for%lwt i = <expr> downto <expr> do
done
]}

- while loop:
{3 While loop}

{[
while%lwt <expr> do
<expr>
done
]}

- pattern matching:
{3 Pattern matching}

{[
match%lwt <expr> with
Expand All @@ -144,7 +165,7 @@ match%lwt <expr> with
| <patt_n> -> <expr_n>
]}

- conditional:
{3 Conditional}

{[
if%lwt <expr> then
Expand Down
Loading