Well I hope you’re intrigued now
I’m reading “OCaml from the very beginning”, I’m on the last chapter and I should reverse the contents of a file, to another file.
This is my entry point:
let rev_file (Valid_path p) =
let ic = open_in p in
let oc = open_out (p ^ ".rev") in
do_rev ic oc
; close_in ic
; close_out oc
;;
I’m only concentrating on do_rev
from now on.
That was my iteration n°1, imperative style:
let do_rev ic oc =
let out = ref [] in
try
while true do
let line = input_line ic in
out := line :: !out
done
with
| End_of_file ->
let output = String.concat "\n" !out ^ "\n" in
output_string oc output
;;
On iteration n°2, I wondered if I could make the code cleaner by making it more functional:
let do_rev ic oc =
let rec build_lines acc =
try build_lines (input_line ic :: acc) with
| End_of_file -> acc
in
let rec put_lines lst =
match lst with
| [] -> ()
| h :: t ->
output_string oc (h ^ "\n")
; put_lines t
in
build_lines [] |> put_lines
;;
At iteration n°3, I saw a pattern and could collapse put_lines
into a terser construct:
let do_rev ic oc =
let rec build_lines acc =
try build_lines (input_line ic :: acc) with
| End_of_file -> acc
in
let output_line line = output_string oc (line ^ "\n") in
let put_lines = List.iter output_line in
build_lines [] |> put_lines
;;
For the final version, I’d like to remove the exception that’s used as a control-flow mechanism. I wondered what I could do with build_lines
if I had a different API to begin with:
let input_line' ic =
try Some (input_line ic) with
| End_of_file -> None
;;
This allows me to “collapse” new_lines
in a similar fashion:
let what_is_it next =
let rec loop next acc =
match next () with
| Some x -> loop next (x :: acc)
| None -> acc
in
loop next []
;;
let do_rev ic oc =
let new_lines = what_is_it (fun () -> input_line' ic) in
let output_line line = output_string oc (line ^ "\n") in
let put_lines = List.iter output_line in
new_lines |> put_lines
;;
However, I’m wondering what the function what_is_it
could be called? It’s similar, but different from all the functions I already know about.
Is there a commonly used function that does the same job? Even in an alternative standard lib? I wouldn’t want to re-invent the wheel.