在 OCaml 中模拟 try-with-finally

2024-01-06

OCaml's try .. with不提供finally像Java这样的子句。不过,它会很有用,尤其是在处理副作用时。例如,我喜欢打开一个文件,将打开的文件传递给一个函数,然后关闭它。如果函数引发异常,我必须捕获它才能有机会关闭文件。当打开多个文件并且打开​​本身也可能失败时,这会变得越来越复杂。是否有既定的编程模式来处理这个问题?

下面是一个简单的函数来说明这个问题。功能f应用于属于文件的通道,如果path被提供并且stdin否则。因为没有finally子句,close_in io出现两次。

let process f  = function 
    | Some path -> 
        let io = open_in path in 
            ( (try f io with exn -> close_in io; raise exn)
            ; close_in io
            )
    | None -> f stdin

是否有既定的编程模式来处理这个问题?

是的,包装函数将资源清理与异常处理分离。我所做的是使用通用包装器,unwind(我比较习惯的一种 LISPism):

let unwind ~(protect:'a -> unit) f x =
  try let y = f x in protect x; y
  with e -> protect x; raise e

这是一个简单的包装器doesn't正确解释中提出的异常protect;一个经过全面检查的包装器,确保protect即使它本身失败也只被调用一次亚龙·明斯基的 https://caml.inria.fr/pub/ml-archives/caml-list/2003/07/5ff669a9d2be35ec585b536e2e0fc7ca.xml,或者我认为这个更清楚一点:

let unwind ~protect f x =
  let module E = struct type 'a t = Left of 'a | Right of exn end in
  let res = try E.Left (f x) with e -> E.Right e in
  let ()  = protect x in
  match res with
  | E.Left  y -> y
  | E.Right e -> raise e

然后,我根据需要定义具体实例,例如:

let with_input_channel inch f =
  unwind ~protect:close_in f inch

let with_output_channel otch f =
  unwind ~protect:close_out f otch

let with_input_file fname =
  with_input_channel (open_in fname)

let with_output_file fname =
  with_output_channel (open_out fname)

我切换特定参数的原因with_功能是我觉得对于高阶编程来说比较方便;特别是,通过定义 Haskell 的应用程序运算符,我可以编写:

let () = with_output_file "foo.txt" $ fun otch ->
  output_string otch "hello, world";
  (* ... *)

语法不是很繁重。对于一个更复杂的示例,请考虑以下内容:

let with_open_graph spec (proc : int -> int -> unit) =
  unwind ~protect:Graphics.close_graph (fun () ->
    proc (Graphics.size_x ()) (Graphics.size_y ());
    ignore (Graphics.wait_next_event [Graphics.Button_down]);
    ignore (Graphics.wait_next_event [Graphics.Button_up]))
    (Graphics.open_graph spec)

可以与类似的调用一起使用with_open_graph " 400x300" $ fun width height -> (*...*).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 OCaml 中模拟 try-with-finally 的相关文章

随机推荐

  • AngularJS 1.2 - ngAnimate 不工作

    我刚开始在 AngularJS 1 2 中使用 ng animate 我不确定为什么我的 ng animate 不能使用某个类名 但可以使用我在示例中看到的简单淡入淡出的默认值 在此示例中 我尝试将 ng animate 类设置为 动画 h
  • numba - guvectorize 只比 jit 快一点

    我试图并行化在许多独立数据集上运行的蒙特卡罗模拟 我发现 numba 的并行 guvectorize 实现仅比 numba jit 实现快 30 40 我找到了这些 1 https stackoverflow com questions 3
  • 如何每 5 分钟执行一次 cron 作业?

    JobDetail job1 JobBuilder newJob FirstJob class withIdentity job1 group1 build Trigger trigger1 TriggerBuilder newTrigge
  • 在 Moq 中为返回 void 的方法分配输出参数

    In 这个问题 https stackoverflow com questions 1068095 assigning out ref parameters in moq 我找到了一个这个答案 https stackoverflow com
  • 修改 Firebase - 动态链接的应用程序预览页面

    有人尝试过从 Firebase 修改此应用程序预览页面吗 我们为其中一个应用程序设置了动态链接并启用了预览页面 我们希望翻译默认字符串 有没有办法翻译一下这句话 保存我在应用程序中的位置 将复制链接以继续此操作 页 以及按钮上的文字 OK
  • 泛型构造函数的好处

    为非泛型类提供泛型构造函数有什么好处 Java 规范允许以下内容 class NonGeneric
  • 如果 isAvailableForServiceType 方法返回 NO 我该怎么办

    如果我能做什么isAvailableForServiceType例如 如果是 Twitter 方法会返回 NO if SLComposeViewController isAvailableForServiceType SLServiceTy
  • 是否可以使用 navigator.share 共享文件(PDF)而不是 url?

    我有一个从服务器生成的 pdf 文件 我希望允许用户通过 navigator share 共享该文件 是否可以共享文件而不是 URL navigator share title Web Fundamentals text Check out
  • 删除由于 gnuplot 中突然跳跃而导致的垂直线

    我正在尝试绘制一个包含 gnuplot 中不连续性的函数 结果 gnuplot 自动绘制一条连接跳跃不连续点的垂直线 我想删除这一行 我环顾四周 发现了两种解决方案 但都不起作用 一种解决方案是使用smooth unique绘图时 另一种是
  • 实际类型的值比较不正确

    我有领域REAL输入数据库 我使用 PostgreSQL 和查询 SELECT FROM my table WHERE my field 0 15 不返回包含以下值的行my field is 0 15 但例如查询 SELECT FROM m
  • VSCode 调试 C++:为什么流程不在断点处停止?

    VSCode 版本 1 3 1 操作系统版本 Ubuntu 14 04 我在 Ubuntu 14 04 上调试 C 项目 我运行 cmake 来生成可执行文件并设置 VSCode 配置文件 当我按F5调试时 程序运行良好 但没有停在断点处
  • 如何显示 Google 字体预览

    我正在将 Google 字体系列名称加载到选择列表中 当用户从列表中选择任何字体系列时 我会动态加载该字体 我的代码 get https www googleapis com webfonts v1 webfonts key functio
  • CakePHP 单元测试装置名称约定 啊?

    我一直在用头撞墙 试图找出为什么我的灯具无法正确加载 当我尝试运行测试时 会呈现我的布局 如果我注释掉该装置 测试就会正常运行 我已经把这个问题看了一百遍了 但我似乎看不出哪里出了问题 这是我的 Videosview test php Ap
  • 如何定量测量源和显示器之间的 gstreamer H264 延迟?

    我有一个项目 我们使用 gstreamer x264 等将视频流通过本地网络多播到多个接收器 连接到显示器的专用计算机 我们在视频源 摄像机 系统和显示监视器上使用 gstreamer 我们使用 RTP 有效负载 96 和 libx264
  • 在 Base SAS 中,如何自动刷新资源管理器?

    我相当确定这一定是困扰其他人的问题 因此必须有一个解决方案 我编写代码并想要快速检查数据集 但它不存在 我需要选择窗口 单击 查看 然后单击 刷新 是否有我可以使用的键盘快捷键或我可以编写的宏来为我做到这一点 我知道这很懒 但它让我烦恼 任
  • 按日期绘制 Twitter 搜索结果的词云? (使用R)

    我希望在 twitter 上搜索一个单词 假设是 google 然后能够生成 twitts 中使用的单词的标签云 但是根据日期 例如 有一个小时的移动窗口 移动时间为每次 10 分钟 并向我展示不同的单词如何在一天中被更频繁地使用 对于如何
  • 如何将 WindowsIdentity 转换为 NetworkCredential?

    我们如何转换一个WindowsIdentity to a NetworkCredential 我正在测试我的 WCF 服务以验证匿名调用者是否被阻止 为此 我想做类似的事情 myProxy ClientCredentials Windows
  • jquery在不同领域检测常用词

    在 jquery 中 如何确定一个元素是否使用了另一个元素中正在使用的单词 例如 如果一个字段包含值 fishbucket 而另一个字段包含fishdome 那么您将如何扫描这两个字段来获取常用词 在本例中为 fish 或者即使是数字 假设
  • 定位jar包内的资源

    我有一个静态类 在该类中图像被加载到 BufferedImage 对象中 如下所示 File groundTopImageFile new File src main resources ground grass top png 现在 当我
  • 在 OCaml 中模拟 try-with-finally

    OCaml s try with不提供finally像Java这样的子句 不过 它会很有用 尤其是在处理副作用时 例如 我喜欢打开一个文件 将打开的文件传递给一个函数 然后关闭它 如果函数引发异常 我必须捕获它才能有机会关闭文件 当打开多个