与 Python 的“with”语句(资源的自动释放)对应的 OCaml 是什么?

vog*_*vog 2 python ocaml raii with-statement

与 Python 的“with”语句对应的 OCaml 是什么?

with open('test.txt', 'r') as f:
    # Do stuff with f
# At this point, f will always be closed, even in case of exceptions
Run Code Online (Sandbox Code Playgroud)

即:OCaml中安全确保某个资源(打开的文件、数据库连接、HTTP 连接等)在某个时间点总是被释放的首选方式是什么?等待垃圾收集器在这里是没有选择的,异常不应该阻止资源被释放。

当然,在 OCaml 中,您始终可以使用 try-finally 并“手动”关闭文件,就像在 Python 中一样。但是,这种代码容易​​出错。这就是 Python 引入“with”语句的原因。什么 OCaml 习惯用法可以使这种代码更易于阅读且不易出错?

请注意,这个问题与在 OCaml 中模拟 try-with-finally的问题非常不同,因为这是更进一步的一步:我不只是想在 OCaml 中模拟 try-finally!(顺便说一下[%finally ...]Lwt做得很好。)我想更进一步,首先不需要编写那些 finally 子句——就像在 Python 中可以做到的那样。

还要注意,这个问题不是关于实现细节,而是关于习惯用法:所有可能的设计和解决方案中哪些在 OCaml 社区中获得了一些牵引力并被普遍接受?

lox*_*oxs 5

JaneStreet 的 core_kernel 标准库替换以In_channel.with_file. 因此,如果您有机会使用 core_kernel,请参阅此处的使用示例: https: //dev.realworldocaml.org/imperative-programming.html#file-io


Yaw*_*war 5

现在可以将Fun.protect视为(有效)惯用语,因为它在标准库中。例如,

let get_contents file =
  let ch = open_in file in
  Fun.protect ~finally:(fun () -> close_in ch) begin fun () ->
    let len = in_channel_length ch in
    let bytes = Bytes.create len in
    ignore (input ch bytes 0 len);
    bytes
  end
Run Code Online (Sandbox Code Playgroud)

如今,甚至还有 let-operators 正在慢慢找到更频繁使用的方​​法,例如https://github.com/ocaml/ocaml/pull/9887

所以你可以定义一个 let-op 来使用一个文件,比如:

let ( let& ) ch fn =
  Fun.protect ~finally:(fun () -> close_in ch) begin fun () ->
    fn ch
  end
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

let get_contents file =
  let& ch = open_in file in
  let len = in_channel_length ch in
  let bytes = Bytes.create len in
  ignore (input ch bytes 0 len);
  bytes
Run Code Online (Sandbox Code Playgroud)

let&操作者可以确保in_channel在当前范围的端部封闭(get_contents)。