例外を使用してファイルの行にわたる繰り返しを中断する

行ごとに操作する必要のあるテキストファイルがいくつかあります。私は以下のように 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*)
);

どんな提案も感謝しています!

4

1 答え

あなたの関数 iter_lines はテール再帰的ではありません。つまり、非常に大きなファイルをこのように処理するとスタックスペースを使い果たすでしょう。それが尾を再帰的にしない理由は、例外を捕まえるために try ... with メカニズムを確立し、解読する必要があるからです。

それ以外は、これは本当によかったよ。この種の高次関数は、OCaml(とFP)のすべてです。

尾を再帰的にする1つの方法は、例外処理を含む関数に例外処理を移動することです。私はまた、あなたが処理したい例外についてより具体的になります。だからあなたはこれを得る:

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

早期に終了したい場合は、handle関数が行の処理を続行するかどうかを指示するブール値を返すようにするのが簡単です。あなたはこのようなものになるでしょう:

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)
6
追加された