有些文本文件需要逐行操作。我写了一个withFile
函数,如下所示:
let withFile fn handle =
let rec iter_lines fh =
try
handle (input_line fh);
iter_lines fh
with _ -> close_in fh in
iter_lines (open_in fn);;
所以我可以将每个文件操作为:
withFile "file1.txt" (fun line -> (*...*))
withFile "file2.txt" (fun line -> (*...*))
...
但是当我不想处理所有线路时,我不确定如何优雅地退出。例如:
withFile "file3.txt" (fun line ->
(*when the line meets some condition, i will exit without handling other lines*)
);
任何建议都表示赞赏!
答案 0 :(得分:6)
您的函数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)