Ваша функция iter_lines
не является хвостовой рекурсией, что означает, что вы, вероятно, исчерпаете свое пространство стека, если обработаете таким образом очень большой файл. Причина, по которой он не является хвостовой рекурсией, заключается в том, что он должен установить и отключить механизм try ... with
для перехвата исключений.
Кроме того, это выглядит очень хорошо для меня. Этот вид функции высшего порядка - вот что такое OCaml (и FP).
Один из способов сделать его рекурсивным - переместить обработку исключений в содержащую функцию. Я также хотел бы быть более конкретным в отношении исключения, которое вы хотите обработать. Итак, вы получите это:
let withFile fn handle =
let rec iter_lines fh =
handle (input_line fh);
iter_lines fh
in
let fh = open_in fn in
try iter_lines fh
with End_of_file -> close_in fh
Если вы хотите иметь возможность досрочного выхода, один из простых способов - заставить вашу функцию дескриптора возвращать логическое значение, указывающее, продолжать ли обработку строк или нет. В итоге вы получите что-то вроде этого:
let withFile fn handle =
let rec iter_lines fh =
if handle (input_line fh) then
iter_lines fh
in
let fh = open_in fn in
try iter_lines fh
with End_of_file -> close_in fh
Если вы хотите использовать исключение для досрочного выхода, вам нужно перехватить все исключения в withFile
, закрыть файл, а затем повторно вызвать любое исключение, кроме End_of_file
. Это дает вам код, который выглядит следующим образом:
let withFile fn handle =
let rec iter_lines fh =
handle (input_line fh);
iter_lines fh
in
let fh = open_in fn in
try iter_lines fh
with e ->
(close_in fh; if e <> End_of_file then raise e)