Lwt — OCaml promises and concurrent I/O 
Краткая справка
Lwt — самая популярная и распространенная монадическая библиотека для асинхронного программирования посредством механизма обещаний (с англ. promises).
В сущности состоит из независимой реализации промисов (библиотека lwt) и реализации взаимодействия с системой и исполнения (resolving) промисов (библиотека lwt.unix).
Основное руководство находится на сайте Ocsigen. Помимо этого библиотека хорошо документирована в коде, как публичный интерфейс так и внутренние вещи.
Помимо прочего активно используется в среде MirageOS.
Анонс 6.x
В новой major-версии библиотеки вводится поддержка direct-style написания асинхронного кода взамен громоздкой монадики и поддержка multicore за счёт использования современных возможностей OCaml 5.
run (fun () ->
  let continue = ref true in
  while !continue do
    match await @@ Lwt_io.read_line ic with
    | line -> await @@ Lwt_io.write_line oc line
    | exception End_of_file -> continue := false
  done)Интересные ссылки
- Заметка о Lwt, Василий Ёркин
 - Детали реализации core'а смотрите в файле 
lwt.mlи т.д.; 
Устройство под капотом
- Lwt: a Cooperative Thread Library — whitepaper про устройство Lwt;
 - CS3110, 8.7. Promises — детальной рассмотрение дизайна и устройства промисов;
 - Скринкаст Промисы под капотом
 - tiny-async-lib — игрушечная библиотека для понимания устройства Lwt, можете также посмотреть видео-разбор его исходного кода и пост с форума;
 - Gist 
dead_simple_read_files_in_lwt.ml; 
Пример
Пример Lwt-программы, которая запрашивает первую страницу Google и терпит неудачу, если запрос не завершен в течение пяти секунд:
open Lwt.Syntax
let () =
  let request =
    let* 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
      Lwt.return (Some response)))
  in
  let timeout =
    let* () = Lwt_unix.sleep 5. in
    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Монадический синтаксис
PPX
ppx_lwt — препроцессинг для удобной монадики с Lwt-промисами.
let%lwt user = get_user_from_api "dad" in
(* ... *)
send_message "some text";%lwtМодуль Lwt.Syntax
let open Lwt.Syntax in
let* user =  get_user_from_api "dad" in
(* ... *)
send_message "some text"Использование в Dune-проекте 
- Произведите установку библиотеки согласно инструкции
 - Добавьте его в ваш 
dune-файл вашего компонентаdune(executable ... (libraries lwt.unix)) 
Использование в Utop 
Utop умееь автоматически резолвить промис.
utop # #require "lwt.unix";;
utop # Lwt.return ();;
- : unit = ()Switches — управление освобождением ресурсов 
См. также
- Рецепт Освобождения ресурсов
 
Библиотека Lwt предоставляет удобную абстракцию под названием switches (свитчи), эдакая область видимости, к которой мы привязываем ресурсы, и по выходу из которой они будут освобождены, даже в случае исключения.
Интерфейс модуля построен так, что он должен быть использован внутри функций с опциональными параметрами.
let connect ?switch uri = 
  let%lwt conn = open_connection uri in 
  (* ... *)
  Lwt_switch.add_hock switch (fun () -> close_connection conn);
  (* ... *)let _ = 
  Lwt_switch.with_switch @@ fun switch ->
  let%lwt conn_a = connect ~switch uri in 
  let%lwt conn_b = connect ~switch uri in 
  (* ... *)Примеры использования
- Применение в библиотеке nats.ocaml
 
Работа с TCP/IP (в примере) 
To-Do
Добавить больше слов что-ли...
TCP клинт 
В реальных проектах
- Nats_lwt.Connection — реализация подключения к NATS серверу;
 
open Lwt.Infix
let host = "127.0.0.1"
and port = 8080
let () =
  Lwt_main.run
  @@ Lwt_io.with_connection
       Unix.(ADDR_INET (inet_addr_of_string host, port))
       (fun (ic, oc) ->
         Lwt_io.write oc "GET / HTTP/1.1\r\n\r\n";%lwt
         Lwt_io.read_line ic >>= Lwt_io.printl)module Tcp_connection = struct
  type t = { ic : Lwt_io.input_channel; oc : Lwt_io.output_channel }
  let create ~host ~port =
    let open Unix in
    (* Создание "сырого" Unix-сокет. *)
    let socket_fd = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
    (* Создание TCP-соединения по указному адресу. *)
    let address = ADDR_INET (inet_addr_of_string host, port) in
    Lwt_unix.connect socket_fd address;%lwt
    (* Оборачивание сокета в удобную абстракцию каналов. *)
    let ic = Lwt_io.of_fd ~mode:Lwt_io.Input socket_fd in
    let oc = Lwt_io.of_fd ~mode:Lwt_io.Output socket_fd in
    Lwt.return { ic; oc }
  let read { ic; _ } = Lwt_io.read ic
  let write { oc; _ } s = Lwt_io.write oc s
  (* Для закрытия сокета достаточно закрыть один из каналов. *)
  let close { ic; _ } = Lwt_io.close ic
end
open Lwt.Infix
let () =
  Lwt_main.run @@
  let%lwt connection = Tcp_connection.create ~host:"127.0.0.1" ~port:8080 in
  (* Чтение и вывод считанной строки в stdout. *)
  Tcp_connection.read connection >>= Lwt_io.printl;%lwt
  Tcp_connection.close connectionTCP сервер 
let serve ~host ~port =
  let%lwt server =
    Lwt_io.establish_server_with_client_address
      (ADDR_INET (Unix.inet_addr_of_string host, port))
    @@ fun _ (_, oc) ->
    Lwt_io.write_line oc "Hello from server!";%lwt
    Lwt_io.flush oc
  in
  let%lwt _ = fst @@ Lwt.wait () in
  Lwt_io.shutdown_server server
let () = Lwt_main.run @@ serve ~host:"127.0.0.1" ~port:8080let serve ~host ~port =
  let socket = Lwt_unix.socket PF_INET SOCK_STREAM 0 in
  Lwt_unix.bind socket (ADDR_INET (Unix.inet_addr_of_string host, port));%lwt
  Lwt_unix.listen socket 10;
  while%lwt true do
    let%lwt client_socket, _ = Lwt_unix.accept socket in
    let oc = Lwt_io.of_fd ~mode:Output client_socket in
    Lwt_io.write_line oc "Hello from server!";%lwt
    Lwt_io.flush oc;%lwt
    
    Lwt_unix.close client_socket
  done;%lwt
  Lwt_unix.close socket
let () = Lwt_main.run @@ serve ~host:"127.0.0.1" ~port:8080Фичи 
Never-промис 
Тут мы создаем промис, который никогда не будет зарезолвен, а значит последовательность не продолжится.
let never = fst @@ Lwt.wait ()let%lwt _ = never in (* ... *)