プログラミング言語 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"のみでは、実行されないため、エラーは発生しない。