为什么要提供“ HasCallStack”机制,因为我们在GHC中已经有“ ghc -prof -fprof-auto-top”?

luo*_*990 6 callstack haskell ghc

AFAIK,有两种方法可以获取调用堆栈以在Haskell中进行调试:

  1. HasCallStack在代码中添加约束
  2. 用编译代码 ghc -prof -fprof-auto-top

我的测试代码:

import GHC.Stack

-- | a wrapper function to make "last" from base traceable
last' :: HasCallStack => [a] -> a
last' xs = case xs of [] -> error "abuse last"; _ -> last xs

-- | a untraceable partial function
foo :: [Int] -> Int
foo xs = last' xs + 1

-- | a untraceable partial function
-- , which looks like traceable, but it's call stack is cut off by "foo"
bar :: HasCallStack => [Int] -> Int
bar xs = foo xs

-- | an empty list
-- , which is also an improper input of "last'"
xs :: [Int]
xs = []

-- | the program is expected to print a call stack telling how "bar" is called
-- , but we can only know that "foo" called "last'" improperly from the printed call stack
main :: IO ()
main = print $ bar xs
Run Code Online (Sandbox Code Playgroud)

以下是我通过上述两种方式通过测试代码获得的调用堆栈:

$ ghc -prof -fprof-auto call-stack-cut-off.hs
$ ./call-stack-cut-off
call-stack-cut-off: abuse last
CallStack (from HasCallStack):
  error, called at call-stack-cut-off.hs:5:29 in main:Main
  last', called at call-stack-cut-off.hs:9:10 in main:Main
CallStack (from -prof):
  Main.last' (call-stack-cut-off.hs:5:1-60)
  Main.foo (call-stack-cut-off.hs:9:1-21)
  Main.bar (call-stack-cut-off.hs:14:1-15)
  Main.main (call-stack-cut-off.hs:24:1-21)
  Main.CAF (<entire-module>)
Run Code Online (Sandbox Code Playgroud)

IMO,来自的调用堆栈-prof已经足够好,并且更易于使用。所以我想知道为什么HasCallStack要添加该机制。这两种方式之间是否存在一些差异,这些差异会严重影响调试体验?

Jon*_*rdy 6

HasCallStack有几个基本优点:

\n\n
    \n
  1. 它\xe2\x80\x99s 更轻量级,不需要-prof,因此它\xe2\x80\x99t 不需要重新编译(因为分析代码与非分析代码具有不同的 ABI)

  2. \n
  3. 它使您可以根据您放置HasCallStack约束的位置以及用于withFrozenCallStack防止不相关/内部详细信息显示在跟踪中的位置,更好地控制调用堆栈中包含的\xe2\x80\x99s

  4. \n
  5. 它允许您使用 访问程序本身内部的调用堆栈getCallStack,因此您可以将其合并到消息中以进行日志记录、异常等

  6. \n
\n

  • 第 1 点有点误导:如果添加 `HasCallStack`,您肯定必须重新编译才能使其生效。我认为你的意思是你不需要像打开分析时那样重新编译其他所有内容(其他模块和库)。 (3认同)