有些文本文件需要逐行操作.我写了一个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);;
Run Code Online (Sandbox Code Playgroud)
所以我可以将每个文件操作为:
withFile "file1.txt" (fun line -> (*...*))
withFile "file2.txt" (fun line -> (*...*))
...
Run Code Online (Sandbox Code Playgroud)
但是当我不想处理所有线路时,我不确定如何优雅地退出.例如:
withFile "file3.txt" (fun line ->
(*when the line meets some condition, i will exit without handling other lines*)
);
Run Code Online (Sandbox Code Playgroud)
任何建议表示赞赏!
您的函数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
Run Code Online (Sandbox Code Playgroud)
如果您希望能够提前退出,一种简单的方法是让您的句柄函数返回一个布尔值,告诉您是否继续处理行.你会得到这样的东西:
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
Run Code Online (Sandbox Code Playgroud)
如果您希望能够使用异常提前退出,则需要捕获所有异常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)
Run Code Online (Sandbox Code Playgroud)