Code review: Is my double `let _ =` necessary in my pipe demo?

I’m trying to learn Unix programming in OCaml, and I just want to make demo of IPC by pipe.

Consider the the example provided by Async docs is too complicated, I simplified it as follows:

(*
 * $ corebuild -pkg async pip102.native
 * $ ./pip102.native
 * *)
open Core
open Async
open Print

module Fd = Unix.Fd

type dumptype =
  {
    a : int;
  } [@@deriving bin_io]

let testdata =
  {
    a = 42;
  }


let start_reader fd =
  let reader = Reader.create fd in
  let _ =
    upon (Reader.read_bin_prot reader bin_reader_dumptype) (function
        | `Ok v -> printf "got data: %d\n" v.a;shutdown 0
        | `Eof ->
          print_endline "Reader success";
          shutdown 0)
  in
  never_returns (Scheduler.go ())

let start_writer pid fd =
  let writer = Writer.create fd in
  let _ =
    let _ =
      Writer.write_bin_prot writer bin_writer_dumptype testdata in
    Writer.close writer
    >>> fun () ->
    let bytes_written = Writer.bytes_written writer in
    printf "Writer success: %s bytes written\n%!"
      (Int63.to_string bytes_written);
    Unix.waitpid_exn pid
    >>> fun () ->
    printf "All successful: transmitted %d messages\n" 1;
    shutdown 0
  in
  never_returns (Scheduler.go ())

let () =
  let module Unix = Core.Unix in
  let ifd, ofd = Unix.pipe () in
  match Unix.fork () with
  | `In_the_child ->
    Unix.close ofd;
    start_reader (Fd.create Fd.Kind.Fifo ifd (Info.of_string "<parent reader>"))
  | `In_the_parent pid ->
    Unix.close ifd;
    start_writer pid (Fd.create Fd.Kind.Fifo ofd (Info.of_string "<child writer>"))

I works:

$ ./pip102.native
Writer success: 348 bytes written
got data: 42
All successful: transmitted 1 messages

But in my code, I have to use lots of let _ = to combine my operation.

let start_reader fd =
  let reader = Reader.create fd in
  let _ =
...


let start_writer pid fd =
  let writer = Writer.create fd in
  let _ =
    let _ =
 ...

I was wondering how may I remove it?

Maybe you could just pipe these values to ignore?

You should used let () = ... for unit expressions. If you use let _ = your expression will match anything on the right hand side (even non-unit values), which weakens the compiler’s ability to warn you.

A lot of IO related functions return unit. You can simply “compose” them with ;:

write handle xyz;
read handle foo;
close handle
1 Like