I'm trying to write a terminal application with Lwt. Basically as longs as my app is running, I need to watch the terminal for input with Lwt_io.read_line.
Is there a better way than the following (pseudocode) to achieve some kind of loop while my program is running?
while true do
let _ = ignore (Lwt_main.run my_application)
done
I'm not sure if this is the right way. Every time all the threads from my_application have finished, the Lwt_main.run gets invoked again & again & again...
Are there other or better ways to handle this with Lwt?
You would typically write your main loop as a recursive function, which evaluates to a thread, then pass that thread once to Lwt_main.run
. Here is a small example:
let () =
let rec echo_loop () =
let%lwt line = Lwt_io.(read_line stdin) in
if line = "exit" then
Lwt.return_unit
else
let%lwt () = Lwt_io.(write_line stdout line) in
echo_loop ()
in
Lwt_main.run (echo_loop ())
This can be compiled and run with:
ocamlfind opt -linkpkg -package lwt.unix -package lwt.ppx code.ml && ./a.out
In rough terms, this is what happens in the above code:
echo_loop ()
is applied in the argument of Lwt_main.run
. This immediately begins evaluating Lwt_io.(read_line stdin)
, but the rest of the code (starting with the if
expression) is put into a closure to be run once the read_line
completes. echo_loop ()
then evaluates to this combination of an ongoing read_line
operation followed by the closure.Lwt_main.run
forces your process to wait until all that completes. However, once the read_line
completes, if the line is not exit
, the closure triggers a write_line
operation, followed by another closure, which calls echo_loop ()
recursively, which starts another read_line
, and this can go on indefinitely.