标准ML例外和资源

时间:2013-06-30 08:35:01

标签: exception resources ml

我想在使用资源期间引发任何异常时释放资源。

在C ++中,这个任务很简单:我把这个版本放到析构函数中,无论发生什么,它都会被自动调用。在Java中,使用'finally'子句。标准ML中同样任务的做法是什么?

我试图用变量模式'e'捕获所有异常并重新提升它:

datatype FileReadResult = FileReadOkay of string | FileReadError

fun read_file (file_path_string : string) : FileReadResult =
    let
        val istream = TextIO.openIn file_path_string
            (* this file is my resource *)
    in
        TextIO.closeIn istream;
        FileReadOkay "" (* the content of the file will go here *)
        handle e => (TextIO.closeIn istream; raise e)
    end
    handle Io => FileReadError

我的编译器(MLton)接受了它,但因为我是ML的新手,我在这里要求保证这是真正正确的事情。最好的做法。

由于这是一种常见的设计模式,我创建了以下效用函数来表达它:

(* Uses the given resource in the given way while releasing it if any exception occurs. *)
fun use_resource (resource : 'Resource) (releaser : 'Resource -> unit) (usage : unit -> 'Result) : 'Result = 
    let
        val r = usage ()
    in
        releaser resource;
        r
    end
    handle e => (releaser resource; raise e)

此功能与C#中的“使用”功能扮演相同的角色。

1 个答案:

答案 0 :(得分:3)

是的,这是通常的模式,有两点需要注意:

  1. 内部handle仅在您的代码中位于FileReadOkay ""周围,不会抛出。您希望将括号放在代码的较大部分周围,以便处理程序适用于所有代码。
  2. 您的外部处理程序捕获Io。我认为你的意思是IO.Io _,否则你会抓住每个异常(因为Io只是一个随机的新变量)。
  3. 如果频繁发生,您也可以尝试将其抽象为函数。

    的内容
    (* withTextFile : string -> (TextIO.instream -> 'a) -> 'a
    fun withTextFile name f =
        let
            val is = TextIO.openIn name
        in
            (f is before TextIO.closeIn is)
            handle e => (TextIO.closeIn is; raise e)
        end
    

    (中缀运算符before计算其左手和右手表达式并返回前者的结果)。使用它像:

    fun echo file = withTextFile file (fn is => print(TextIO.inputAll is))