This is my first OCaml program. Advices for improvement?

So it removes '\n’s from clipboard buffer, so I can paste the content to any translation software later. If I don’t remove the NEWLINEs, the translator softwares could give me wrong translations

let () = print_endline "Removing NEWLINE from clipboard..."

let run cmd: string =
    let fd = Unix.open_process_in cmd in
    let () = Printf.printf "[i] Running command '%s'\n" cmd in
    let text = In_channel.input_all fd in
    let _ = Unix.close_process_in fd in
    text

let remove_newline str: string =
    str
    |> String.map
       @@ fun c -> if c = '\n' then ' ' else c

let () =
    let () = print_endline "[i] Initializing main" in
    let global_buffer: string ref = ref "(empty)" in
    while true do
        let () = Unix.sleep 1 in
        run "pbpaste"
        |> remove_newline
        |> fun str -> if str = !global_buffer then
            let () = print_endline "    No change found." in
            ()
        else
                let () = global_buffer := str in
                Printf.printf "[i] Buffer updated.\n\n<><><>Content<><><>\n%s\n" !global_buffer
    done

I’m using macOS Big Sur so I used pbcopy and pbpaste

Hi,
Congrats on writing your first program. This is good!
Here are some comments for improvement:

  • use a formatting tool
  • it’s unusual to annotate return values (for run or global_buffer for example). the compiler can infer that and humans can use merlin.
  • in remove_newline, don’t mix |> with @@.
  • you can use String.trim and iterate on lines (In_channel.input_lines) instead of defining that function to avoid inserting spaces.
  • I would recommend putting all “execution” code (the first let () on top and the second larger one in a main function and have a single let () = main () at the end)
  • you can use a;b to sequence expressions instead of using let () = a in b. in particular let () = x in () is equivalent to x
  • instead of a |> fun b -> c you can use let b = a in c (in your case, let str = run "pbpaste" |> remove_newline in if str = ...)
  • where is pbcopy used? this seems to just print the string.
3 Likes

Thank you very much!

  • Now I’m downloading ocamlformat with opam and I’m ready to give dune fmt a try
  • I tried In_channel.input_lines but OCaml told me this function does not exist? (both OCaml version 4 and 5)
  • So writing a main () is like writing if __name__ == "__main__" in Python, I guess :stuck_out_tongue_winking_eye:
  • I realized that I did not use pbcopy in this code, and that was a mistake
  • Thanks for your reply :smiling_face_with_three_hearts:
1 Like

Sorry, I meant input_line. You can either use that (you’ll need to somehow call that in a loop), or use String.split_on_char to turn the file contents into a list of strings.

1 Like