在 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 的相关文章

  • 如何解决声纳中的 dodgy:unchecked/unconfirmedcast 问题?

    我在下面的代码中通过声纳获得异常 我该如何解决这个问题 建议我 Override public boolean validate BaseInfo infoObject boolean isValid true AckTransferPay
  • 抛出 UnsupportedOperationException

    因此其中一种方法的描述如下 public BasicLinkedList addToFront T data 该操作无效 对于排序列表 将生成 UnsupportedOperationException 使用消息 排序列表的操作无效 我的代
  • 如何在 Ocaml 中表示一个简单的有限状态机?

    我用 C 和 Java 编写过一些状态机 但从未用过像 Ocaml 这样的函数式语言 问题是我不知道我是否可以从对象语言版本中调整代码 因为在 Ocaml 中记录和变体比类更强大 所以 我需要一个事件驱动的有限状态机 像 UML 中的分层结
  • rmi类找不到异常

    我使用 java rmi 编写了一个简单的项目并导出到可执行 jar 文件 当我尝试运行它时 有时会出现异常 有时会起作用 当我指定 Djava rmi server codebase file serverClasses 时 它似乎没有正
  • 关于pl/sql异常的问题

    以下文字摘录自oracle文档Oracle Database PL SQL 语言参考 11g 第 1 版 11 1 未处理的异常也会影响 子程序 如果退出子程序 成功后 PL SQL 将值分配给 输出参数 但是 如果您退出 带有未处理的异常
  • C++ 中的错误分配异常

    在我的一个学校项目中 我被要求创建一个程序而不使用STL 在程序中我使用了很多 Pointer new Something if Pointer NULL throw AllocationError 我的问题是关于分配错误 有没有一个自动例
  • 在哪里捕获异常

    我有一个 WCF svc 分为服务层 业务逻辑层和数据访问层 当我的 DAL 遇到异常时 我应该在那里捕获它还是让它冒泡回到服务层 为什么 请忽略此场景中的任何客户端参与 我只关心在 WCF svc 上记录异常 有一个术语 异常屏蔽 基本上
  • Ruby“定义”?操作员工作错误?

    所以 我们有代码 class Foo def bar puts Before existent defined some variable puts Before not existent defined nonexistent varia
  • 包含多列查询

    当任一列可能为空时 如何使用 LINQ to SQL 搜索多个列 IEnumerable
  • 使用 LINQ 分割字符串

    我想按我的结果和字符串行中的匹配数进行排序 所以这是代码 ThenByDescending p gt p Title ToLower Split Count w gt words Any w Contains 但它给我带来错误并说 LINQ
  • 如何使用 Python 正确传播错误消息

    我对正确的 Python 错误处理有点陌生 并且我很难找到处理多种方法链中的错误的最佳方法 我有3种方法 a b c a正在打电话b and b正在打电话c 如何从方法中传播错误c回到方法a所以我可以例如将其存储在某处或在 API 响应期间
  • 为什么单线程异常会导致整个程序崩溃(如何防止这种情况?)

    例如 如果我跑步 int x 0x00000 程序崩溃了 但为什么整个程序崩溃而不是单个线程崩溃呢 我创建了多个连续睡眠的线程来测试这一点 有什么方法可以让当前线程退出 而不是整个程序 在Windows上使用winapi Thanks 但为
  • Nunit 测试给出结果 OneTimeSetUp: 未找到合适的构造函数

    我有一个问题 NUnit 告诉我 没有找到合适的构造函数 这是什么原因造成的 我还收到另一条消息 异常没有堆栈跟踪 这两条消息只是一遍又一遍地重复 这是我的代码 TestFixture public class SecurityServic
  • Haskell 错误处理方法

    毫无疑问 Haskell 中有多种机制来处理错误并正确处理它们 错误单子 要么 也许 异常等 那么为什么用其他语言编写容易出现异常的代码比用 Haskell 感觉更简单呢 假设我想编写一个命令行工具来处理命令行上传递的文件 我想 验证提供的
  • 由于 3rd 方库的位置,启动 Solr cloud 时出错

    我尝试迁移到 Solr 3 1 我的项目使用 Dataimport handler 当我启动 solr 时 它问我找不到 SolrCoreAwar 我将以下文件复制到 lib 目录 apache solr dataimporthandler
  • XAML解析异常

    我有一个简单的 XAML 页面 当它作为 Visual Studio 中任何应用程序的一部分加载时 加载效果良好 但是 当我使用 ClickOnce 部署此应用程序时 出现以下异常 Type System Windows Markup Xa
  • 使用 F5 时,finally 似乎没有在 C# 控制台应用程序中执行

    int i 0 try int j 10 i catch IOException e finally Console WriteLine In finally Console ReadLine 在VS2008中按F5时 finally块似乎
  • “包含非 LDH ASCII 字符”异常从何而来?

    我开发了一个应用程序 spring magnolia 它在新年 2018 左右开始为我抛出这个异常 但不为任何其他同事抛出异常 例外是正确的 有一个 在配置的主机名中 因此域名应该是固定的 尽管如此 它之前一直在工作 对于其他人来说它仍然在
  • 第一次机会异常 - 在内存位置长?

    这是什么 我该如何处理 修复它 First chance exception at 0x756fb727 in Program exe Microsoft C exception long at memory location 0x0018
  • 未捕获 Func<> 的异常(异步)

    我有以下代码 为了进行此重现而进行了简化 显然 catch 异常块将包含更多逻辑 我有以下代码 void Main var result ExecuteAction async gt Will contain real async code

随机推荐

  • 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这样的子句 不过 它会很有用 尤其是在处理副作用时 例如 我喜欢打开一个文件 将打开的文件传递给一个函数 然后关闭它 如果函数引发异常 我必须捕获它才能有机会关闭文件 当打开多个