2010-01-26 105 views
14

如何獲得有關發生Haskell錯誤的更多信息?例如,昨天我正在研究一個Haskell程序,它解析輸入文件,轉換數據並打印出報告信息。跟蹤Haskell中的錯誤

在一個點上,我跑了「主」和回來

*** Prelude.read: parse error 

沒有其他信息。幸運的是,我知道我是在只有一個地方調用read,並能修復它,但對於未來:

  • 是否有可能得到一個回溯或類似這些錯誤的行號?
  • 是否可以獲取觸發錯誤的實際數據,即導致解析錯誤的字符串?

謝謝!

編輯使用GHC。

+0

你最好完全避免部分函數。改用'Safe.readMay'。 – 2014-01-30 14:34:10

+0

看到[這裏](http://stackoverflow.com/questions/8595077/how-can-i-get-the-position-where-error-was-called)爲更好的解決方案 – Simon 2014-12-29 17:35:30

回答

5

你可以得到通過導入Debug.Trace,改變 你造成了解析錯誤的字符串r電話

 
import Debug.Trace (trace) 

--change 
myRead s = read s 
--to 
myRead s = trace s (read s) 
--or 
myRead s = trace (take 100 s) (read s) 
+0

我發現'\ s-> fst $ head $ reads s ++ [error $「無法讀取:」++ show s]'更有用,因爲讀取成功時它不會發送垃圾郵件。 – Rotsor 2012-06-21 19:36:19

2

你沒有告訴我們你正在使用哪個編譯器。如果你使用GHC,那麼你應該看看GHCi Debugger

Haskell中的堆棧跟蹤並不平凡,因爲它的懶惰。不過,前面提到的調試器提供了一些工具(參見上述UR​​L中的2.5.5。跟蹤和歷史記錄)。

3

一般來說它是由你來處理錯誤以這樣的方式,有背景足夠你調試的原因。

哈斯克爾的lazyness使得堆棧跟蹤,難以實施,因爲調用堆棧可能不存在任何再被錯誤發生的時間。

的錯誤處理的一種簡單方法是在一個錯誤的情況下,使用任何一種類型,它允許您返回一個值時,事情發生了吧,或者一些上下文(錯誤信息,輸入字符串,...)。

最後,在您的具體情況下,read正在拋出異常,因此您必須先捕獲該異常,然後處理調用代碼中的錯誤(查看Control.Exception包)。

1

您可以考慮使用一個單子read"Practical Haskell: shell scripting with error handling and privilege separation"同胞StackOverflow的用戶dons

的第一步是用版本提升到一個通用的錯誤單子更換readMonadError

readM :: (MonadError String m, Read a) => String -> m a 
readM s | [x] <- parse = return x 
     | otherwise = throwError $ "Failed parse: " ++ show s 
    where 
     parse = [x | (x,t) <- reads s] 
7

如果你可以在ghci中運行代碼,那麼調試器可以做你想做的一切。下面是拋出一個異常

foo s i 
    | i == 57 = read s 
    | otherwise = i 
main = mapM_ (print . foo "") [1..100] 

現在將其加載到ghci中,並使用調試器,如記錄在這裏的程序: http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#ghci-debugger-exceptions

> ghci test.hs 
*Main> :set -fbreak-on-error 
*Main> :trace main 
1 
2 
... snipped 3 through 55 ... 
56 
Stopped at <exception thrown> 
_exception :: e = _ 
[<exception thrown>] *Main> :back 
Logged breakpoint at test.hs:2:15-20 
_result :: a 
s :: String 
[-1: test.hs:2:15-20] *Main> :list 
1 foo s i 
2 | i == 57 = **read s** 
3 | otherwise = i 
[-1: test.hs:2:15-20] *Main> s 
"" 
[-1: test.hs:2:15-20] *Main> 

它可以讓你在評價歷史周圍一步,突出了實際表達式引發異常(加粗而不是在終端上加星標),並讓您檢查局部變量。

另一種選擇是分析重新編譯和一些標誌標記相應的成本中心,並與打印在捕獲的異常 http://www.haskell.org/ghc/docs/latest/html/users_guide/prof-time-options.html

> ghc -prof -auto-all test.hs 
> ./test +RTS -cs 
1 
2 
... snipped 3 through 55 ... 
56 
*** Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace: 
    Main.foo, 
    called from Main.main, 
    called from Main.CAF 
    --> evaluated by: Main.main, 
    called from Main.CAF 
test: Prelude.read: no parse 

的原因,這是成本中心棧-xc分析選項運行有點困難在調試器頁面上稍早介紹一下 http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#tracing 基本上,高效的Haskell執行不會使用類似於普通調用堆棧的任何東西,因此要獲取有關異常的信息,必須在某些特殊模式下運行(調試或分析),它確實保持了這一點種類的信息。