2017-08-08 91 views
1

如果一個程序運行並且出現「零除」的消息,那麼識別代碼中哪裏出現這個錯誤的最好方法是什麼?如何用ghc 7.10.3除零產生堆棧軌跡?

+0

你可以限定「最好」嗎?一般來說,堆棧跟蹤在懶惰的函數式語言中並沒有你所期望的那麼有意義,所以可能你最好的選擇是啓用分析。否則,請使用['CallStack'](https://hackage.haskell.org/package/base-4.10.0.0/docs/GHC-Stack.html)。 – user2407038

+0

我想我會解決任何識別錯誤發生的源代碼中的行的方法。當你說啓用性能分析時,這是否意味着我可以使用一些額外的參數(哪些?)運行'stack build',然後當我執行程序時,它會伴隨更多信息的錯誤? – kostmo

回答

1

GHC不支持堆棧跟蹤,因爲沒有調用堆棧。您可以做的最好的方法是在基本模塊GHC.Stack中使用模擬堆棧跟蹤機器。

與GHC 7.8開始,並且因此在7.10.3可用,GHC.Stack暴露

errorWithStackTrace :: String -> a 

作用就像error上正常建立但使用SCC的註釋(例如,從--fprof-auto)來構造一個近似堆棧跟蹤在異形構建。您將需要重新編譯啓用分析以支持此功能。如果您正在使用cabal,則可以運行

cabal configure --enable-library-profiling --enable-executable-profiling 

並重建。

從GHC 8.0開始,errorWithStackTrace已棄用,並且由HasCallStack機器提供對呼叫站生成的支持。

GHC.Stack文檔現在報價,

函數可以用HasCallStack約束要求其調用點。例如,我們可以定義

errorWithCallStack :: HasCallStack => String -> a 

error變體,將得到其調用點。我們可以通過callStack訪問errorWithCallStack內的調用棧。

errorWithCallStack :: HasCallStack => String -> a 
errorWithCallStack msg = error (msg ++ "n" ++ prettyCallStack callStack) 

因此,如果我們調用errorWithCallStack我們將得到一個格式化的調用堆棧與我們的錯誤消息。

>>> errorWithCallStack "die" 
*** Exception: die 
CallStack (from HasCallStack): 
    errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1 

(我猜msg ++ "\n"了意思,但"n"是怎樣寫的。)

雖然你可以用GHC 7.8和獲得一些非常有限的堆棧跟蹤的支持,我會建議升級如果可能的話,以GHC 8爲明顯更好的支持。無論哪種方式,它不會是你從其他語言習慣的,但它總比沒有好。

+0

在最新的GHC版本中,'error' *是*'errorWithCallStack'。而且這些文檔似乎表明你比使用'HasCallStack'獲得更好的配置文件的堆棧跟蹤。我還沒有嘗試過配置文件的方式。 – dfeuer

+0

@dfeuer我是否正確理解GHC 8.2.1 w /'-prof'應該產生更好的調用棧?它似乎並不如此:https://gist.github。com/TomMD/7d1fb8dc762fc37bf80b7b7dd447e29a –

+0

即使啓用性能分析(通過'stack build --profile'),我只看到錯誤消息「除以零」,沒有額外的上下文。假設有一個代碼庫,其中除法操作('/'或'\'div \'')出現在幾十個呼叫站點。如果在運行時遇到錯誤消息「被零除」,並且任何這些調用站點似乎都可能成爲錯誤源,那麼如何調試呢?必須用一些帶註釋的版本來替換除法操作的每個實例(充其量,縮小二進制搜索中的違規呼叫站點)? – kostmo