Зачем предоставлять механизм HasCallStack, поскольку у нас уже есть GHC -prof -fprof-auto-top в GHC? - PullRequest
6 голосов
/ 18 июня 2019

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

Ниже приведен стек вызовов, который я получаю обоими вышеупомянутыми двумя способами, используя этот тестовый код:

$ 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>)

IMO, стек вызовов из -prof уже достаточно хорош и проще в использовании. Поэтому мне интересно, почему механизм HasCallStack добавлен еще. Есть ли какая-то разница между этими двумя способами, которая существенно повлияет на процесс отладки?

1 Ответ

4 голосов
/ 18 июня 2019

HasCallStack имеет несколько основных преимуществ:

  1. Он легче, не требует -prof, поэтому не требует перекомпиляции (поскольку профилированный код имеет другой ABIчем непрофилированный код)

  2. Это дает вам больший контроль над тем, что включено в стек вызовов, в зависимости от того, где вы размещаете ограничения HasCallStack и где вы используете withFrozenCallStack для предотвращения ненужных/ Внутренние детали отображаются в следах

  3. Это позволяет вам получить доступ к стеку вызовов из самой программы, используя getCallStack, так что вы можете включить его в сообщения для регистрации, исключений,и так далее

...