`onException` 的行为方式

2024-03-10

finally and onException是模块中的两个函数Control.Exception,它们具有相同的签名但行为不同。Here https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.11.1.0/Control-Exception.html#v:onException是文档。 为了finally, 它说:

finally 
:: IO a  -- computation to run first
-> IO b  -- computation to run afterward (even if an exception was raised)
-> IO a

,同时对于onException, 它说:

Like finally,但仅在存在时才执行最终操作 计算引发的异常。

所以我做了以下测试:

ghci> finally (return $ div 4 2) (putStrLn "Oops!")
Oops!
2
ghci> finally (return $ div 4 0) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero

其行为符合预期。

然而,onException才不是:

ghci> onException (return $ div 4 2) (putStrLn "Oops!")
2
ghci> onException (return $ div 4 0) (putStrLn "Oops!")  -- does not act as expected
*** Exception: divide by zero

如上所述,onException仅在引发异常时执行最终操作,但上面的示例表明onException不执行最终操作,即putStrLn "Oops!"当发生异常时。

检查后源代码 https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.11.1.0/src/Control.Exception.Base.html#onException for onException,我尝试如下测试:

ghci> throwIO (SomeException DivideByZero) `catch` \e -> do {_ <- putStrLn "Oops!"; throwIO (e :: SomeException)}
Oops!
*** Exception: divide by zero
ghci> onException (throwIO (SomeException DivideByZero)) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero

可以看出,当显式引发异常时,将执行最终操作。

所以问题是return $ div 4 0确实抛出异常,但是why onException (return $ div 4 0) (putStrLn "Oops!")不执行最后的动作putStrLn "Oops!"?我缺少什么?以及异常是如何执行的?

ghci> throwIO (SomeException DivideByZero)
*** Exception: divide by zero
ghci> (return $ div 4 0) :: IO Int
*** Exception: divide by zero

你已经被懒惰的评价所困扰了。

的关键保证之一throwIO是它保证when例外情况将在执行其他IO行动。从文档 https://hackage.haskell.org/package/base-4.11.1.0/docs/Control-Exception.html#v:throwIO:

虽然throwIO具有一个类型,该类型是以下类型的实例throw,这两个函数略有不同:

throw e   `seq` x  ===> throw e
throwIO e `seq` x  ===> x

第一个例子会导致异常e会被提出,而第二个则不会。实际上,throwIO仅当在以下范围内使用时才会引发异常IO单子。这throwIO应该优先使用变体来引发异常IOmonad 因为它保证相对于其他的排序IO操作,而throw才不是。

这意味着,当throwIO e动作被执行(不仅仅是评估!)作为执行所产生的动作的一部分onException,保证确实会引发异常。由于异常是在异常处理程序执行的动态范围内引发的,因此会检测到异常并执行处理程序函数。

然而,当你写return e,它产生的动作确实not评价e执行时为 WHNF,并且e仅当/当操作的结果本身被评估时才被评估。到时候div 4 0表达是由 GHCi 强制的show在执行动作的结果时,控制已经离开了执行的动态范围onException,并且它安装的处理程序不再位于堆栈中。异常已引发,但引发得太晚了。

为了获得您想要的行为,确保您进行评估至关重要div 4 0作为行动执行的一部分,而不是之前或之后的一刻。这是什么the evaluate函数来自Control.Exception https://hackage.haskell.org/package/base-4.11.1.0/docs/Control-Exception.html#v:evaluate是为了.它评估 WHNF 的参数作为执行的一部分IO操作本身,保证作为该评估的一部分引发的任何异常都将被周围的异常处理程序检测到:

ghci> onException (evaluate $ div 4 0) (putStrLn "Oops!")
Oops!
*** Exception: divide by zero

道德:在 Haskell 中处理异常时,要非常小心评估事物的时间,以确保异常是在异常处理程序的动态范围内引发的,并且不会由于延迟评估而被推迟。

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

`onException` 的行为方式 的相关文章

随机推荐

  • 更新日期 + mysql 中的一年

    当我想在 mysql 表中设置数值 1 时 我使用例如 UPDATE table SET number number 1 WHEN 如何设置日期 一年 Thanks 你可以使用DATE ADD http dev mysql com doc
  • 在 IPython 控制台中运行内核的问题

    我的 Python Spyder 软件 版本 4 0 1 在 IPython 控制台中运行内核时遇到问题 因此 我尝试了很多方法来解决该问题 例如在 Anaconda 提示符中运行一些命令或将设置设置为默认模式 我什至更新了我的 anaco
  • 如何使用 STL 算法查找 2D 数组中列值的最大值和最小值

    我有一个 2D 数组 整数向量的向量 其中包含如下 int 值 34 19 89 45 21 34 67 32 87 12 23 18 我想找到列值 而不是行值 的最大值和最小值 最好使用STL算法 std max element std
  • SQL Server 中的临时表

    我正在研究在sql server 中创建临时表 我成功创建了临时表 但是当我尝试查看数据时 它显示无效的对象名称 谁能告诉敌人临时表存在多长时间 如果我以 userid devloper 和 pwd 0999 身份登录到 sql serve
  • 覆盖/更新浏览器cookie

    我有一个 Express 4 x 应用程序 我将 cookie 传递给浏览器 res cookie foo bar1 maxAge 99999999999 它在遥远的未来到期 然而 5 分钟后 我收到来自同一用户的另一个请求 我想给他们一个
  • 我们应该始终绑定 SQL 语句吗?

    我一直在研究PDObindValue 我知道使用 PDO 准备 SQL 语句可以防止 SQL 注入的发生 代码示例 stmt dbh gt prepare SELECT FROM articles WHERE id id AND title
  • 在 Vite.js 项目中使用 `compilerOptions.baseUrl` ?

    我正在尝试从 Create React App 迁移到 Vite js 但我遇到了导入别名问题 在创建 React 应用程序中我有一个jsconfig json文件与compilerOptions baseUrl set to src 所以
  • 填充 Pandas 数据框中两列之间的数字

    我有一个带有以下几列的 Pandas 数据框 id start end 1 101 101 2 102 104 3 108 109 我想用附加行填充开始和结束之间的空白 因此输出可能如下所示 id number 1 101 2 102 2
  • 交换 NSMutableArray 中的元素

    是否有任何特殊方法可以使 NSMutableArray 中的元素交换更容易或更直接 交换ObjectAtIndex 与ObjectAtIndex http developer apple com library mac documentat
  • 使用可能挂起的 API 强制取消任务

    我目前正在使用串行端口 并且我使用的 API 有时会挂在读取上 即使设置了自己的超时也是如此 这不是一个大问题 但是当发生这种情况并且挂起的线程需要关闭时我需要做一些工作 我已经尝试过以下操作 但它一直给我带来问题 因为 API 调用没有终
  • 如何使用 fetch api 发布表单数据?

    My code fetch api xxx body new FormData document getElementById form headers Content Type application x www form urlenco
  • 如何在对象切片时生成编译器警告/错误

    我想知道是否可以让编译器发出警告 错误代码 如下所示 Note 1 年 这是不好的编程风格 我们应该避免这种情况 但我们正在处理遗留代码 希望编译器可以帮助我们识别这种情况 2 我更喜欢使用编译器选项 VC 来禁用或启用对象切片 如果有 c
  • 从 Shiny (R) pt 下载 png。 2

    这与我之前问过的一个问题有关 从 Shiny R 下载 png https stackoverflow com questions 26764481 downloading png from shiny r 我现在已经创建了多个闪亮的图并下
  • 如何将 jar 文件包含到 Oracle 中的 Java 存储过程中?

    我正在实现一个存储过程 现在需要能够将 jar 文件包含到我的存储过程中 这些文件不属于 JRE 的标准部署 我怎样才能做到这一点 据我所知 Oracle 9 不可能做到这一点 感谢帮助 使用 loadjava 工具 它也接受 jar 文件
  • 用Python的pyaudio列出所有音频设备(portaudio绑定)

    I tried import pyaudio p pyaudio PyAudio for i in range p get device count print p get device info by index i 但我没有获得所有设备
  • 如何在 Bash 或 grep 或批处理中删除 HTML 文件的所有链接并将它们存储在文本文件中

    我有一个文件是HTML http en wikipedia org wiki HTML 它有大约 150 个锚标记 我只需要这些标签的链接 又名 a href a 我只想得到http www google com http www goog
  • 是否可以使用 AWS SAM 配置具有不同 lambda 版本的不同 API Gateway 阶段

    我有一个适用于我的应用程序的 SAM 模板 每次我使用新的 API 网关阶段名称部署 SAM 模板时 它都会替换之前创建的阶段 因此 发现这篇文章可以帮助我发布指向不同 lambda 版本的不同版本 https aws amazon com
  • 通用类型转换[重复]

    这个问题在这里已经有答案了 我有以下课程 简化但仍然是一个有效的示例 class Test
  • RxTest:架构 x86_64 和 arm64 的未定义符号

    我正在尝试运行以下测试第 16 章 使用 RxTest 进行测试 of Raywenderlich RxSwift https store raywenderlich com products rxswift book import XCT
  • `onException` 的行为方式

    finally and onException是模块中的两个函数Control Exception 它们具有相同的签名但行为不同 Here https downloads haskell org ghc latest docs html l