使用异常来突破文件行的迭代

时间:2011-11-12 01:11:38

标签: exception ocaml

有些文本文件需要逐行操作。我写了一个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*)
);

任何建议都表示赞赏!

1 个答案:

答案 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)