haskell - 如何使用CallStack抛出异常?

标签 haskell exception

我有异常类型 UnknownException,我希望在抛出该异常时包含 CallStack。

module Main where

import Control.Exception (Exception, throw)

newtype UnknownException = UnknownException
  { caller :: String
  } deriving (Show)

instance Exception UnknownException

main :: IO ()
main = willThrow

willThrow :: IO ()
willThrow = throw $ UnknownException "willThrow"

我希望上面的示例能够像这样打印日志

example-exe: UnknownException {caller = "willThrow"}
CallStack (from HasCallStack):
  willThrow, called at app/Main.hs:16:13 in main:Main
  main, called at app/Main.hs:13:8 in main:Main

但实际打印:

example-exe: UnknownException {caller = "willThrow"}

此外,在 Haskell 中将 CallStack 包含在异常中是一个好习惯吗?

最佳答案

是的,我认为这是一个很好的做法。如果您使用分析进行编译,则只需使用

currentCallStack :: IO [String]

来自GHC.Stack 。请注意,它位于 IO 中,但如果您使用的是纯代码,那么当您抛出错误时,我认为使用 unsafePerformIO 就可以了。因为所有底部在含义上都是平等的,所以实际上并没有任何违反纯度的情况。

但是,如果您想在不进行分析的情况下获取调用堆栈(假设您想将其包含在生产的日志消息中),则必须做更多的事情。您必须包括 HasCallStack您希望报告堆栈的任何地方都有约束。所以

main :: IO ()
main = print f

f :: Int
f = g

g :: HasCallStack => Int
g = h

h :: HasCallStack => Int
h = error (show callStack)

将报告最多 g 的调用堆栈,但将省略 f。可悲的是,

If there is no CallStack in scope and the enclosing definition has an explicit type signature, GHC will solve the HasCallStack constraint for the singleton CallStack containing just the current call-site.

这意味着它将忽略 f 的任何调用者,即使他们确实有 HasCallStack 只是因为 f 没有这样的约束。我觉得这非常麻烦。 这是一个相当新的功能,所以我希望 GHC 团队有更好的想法,他们可以利用它来实现。

关于haskell - 如何使用CallStack抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53999891/

相关文章:

haskell - 如何运行通过命令参数传递给解释器的 haskell 代码?

haskell - 嵌套纯函数中的随机性

string - Haskell 操作文件内容

java - 尝试查找元素时如何使用列表上的流抛出异常?

python - 如何区分两个 numpy FloatingPointError 异常?

exception - 机器人框架异常成功

haskell - 列表推导式中的 where 子句

haskell - 为 Haskell 项目安排辅助任务

c++ - 如何在Windows异常处理程序中设置MMX寄存器以模拟不受支持的3DNow!指示

安卓 : SQLiteException: not an error not on all devices