プログラミング言語 Standard ML 入門 (問題の解答例)
15.5 入出力エラーの処理
問 15.9
以前作成したファイル変換関数に上記の入出力エラー処理を加え,
- lowerFile "foo.txt";
IO Error : openIn failed. No such file or directory : foo.txt
val it = () : unit
のようにエラーメッセージを表示するように改良せよ.
解答例 教科書本文にある通り、例外 IO.Io name:string, function:string, cause:exn を以下のようにhandleすればよい。 このエラー処理はlowerFile関数に以下のように追加できる。
fun lowerFile inf outf =
filterFile Char.toLower inf outf
handle IO.Io {name,function,cause} =>
(print ("IO Error : " ^ function ^ " faild. ");
case cause of
OS.SysErr (s,e) => print (s ^ ": ")
| _ => print (exnMessage cause ^ ": ");
print (name ^ "\n"))
しかし、エラーを処理しプログラムを継続する場合には、オープンして いるファイルのクローズ処理をするのが望ましい。 そこで、ファイルをオープンする関数lowerFileでエラー処理も 行うのがより適当である。 ただ、lowerFileは2つのファイルをオープンしており、クロー ズ処理が必要なオープン済みストリームはプログラムコードの位置に依存する。 この問題を系統的に処理する一つの方法は、ファイナライザ (finalizer)関数をエラー処理に渡す手法がある。 以下はその例である。
exception Abort
fun IOhandler ({name,function,cause}, finalizer) =
(print ("IO Error : " ^ function ^ " faild. ");
case cause of
OS.SysErr (s,e) => print (s ^ ": ")
| _ => print (exnMessage cause ^ ": ");
print (name ^ "\n");
finalizer();
raise Abort)
fun filterFile f inf outf =
let val ins = openIn inf
handle IO.Io param =>
IOhandler (param,fn () => ())
val outs = openOut outf
handle IO.Io param =>
IOhandler (param,fn () => closeIn ins)
in
(filterStream f ins outs
handle IO.Io param =>
IOhandler
(param,
fn () => (TextIO.closeIn ins;
TextIO.closeOut outs));
closeIn ins;
closeOut outs)
end
handle Abort => ()
fun lowerFile inf outf = filterFile Char.toLower inf outf
上記何れの場合も、SML#で以下のような実行結果となる。
# lowerFile "foo.txt"; val it = fn : string -> unit # lowerFile "foo.txt" "bar.txt"; IO Error : openIn faild. No such file or directory: foo.txt val it = () : unit
なお、例から分かる通り、lowerFileは2つの引数を取る関数であり、 lowerFile "foo.txt"のみでは、実行されないため、エラーは発生しない。