2011-09-11 30 views
0

我複製了 (http://www.haskell.org/haskellwiki/Euler_problems/11_to_20#Problem_11)給出的Euler.11解決方案,但它失敗並出現索引錯誤:「(Array。!):undefined array element」。 當然,首先我想要一個更好的錯誤消息(!),甚至可能會提供失敗的索引,但如果失敗,我嘗試調試它。調試列表理解

的數據被輸入正確,並且它的一個打印示出右界限,和數據。

所以我增加了一些跟蹤消息,這兩個結果的表達和理解的身體。我從最終表達式中得到很多跟蹤結果,但沒有一個來自身體計算。爲什麼?

prods :: Array (Int, Int) Int -> [Int] 
-- trace ("xs: " ++ show xs) (product xs) 
prods a = [trace ("xs: " ++ show xs) (product xs) | i <- range $ bounds a, 
         s <- senses, 
         let trace1 = check "i: " i, 
         let is = take 4 $ iterate s i, 
         let trace2 = check "is: " is, 
         all (inArray a) is, 
         let xs = map (a!) is] 

-- Doit 
-- euler = print . maximum . prods . input =<< getContents 
euler eData = maximum . prods $ input eData 

-- Debugging tracecheck :: String -> a -> a 
check msg v | trace (msg ++ (show v)) True = v 

回答

2

首先,使錯誤信息包括髮生故障的索引將需要Show約束將被添加到陣列索引,這可能是不希望的。

第二,如羅馬說,消息不被懶惰因爲評價的印刷。 Bang-patterns(let !trace = check "i: " i)可能是規避它的最方便的方式,但我不清楚列表解析中的這些工作。

接下來,undefined array element消息告訴您數組構造不正確(某些元素未定義),因此您需要調試構造它的函數而不是使用它的函數。

+0

非常感謝所有觀點;似乎很明顯(現在!)。我在構建完數組後打印了這個數組,它看起來都很好,並且具有預期的邊界。我會多花些時間看看它是如何得到一些未定義的值。 – guthrie

+0

你對數據的錯誤設置是正確的 - 我錯誤地解釋了錯誤信息。 – guthrie

5

Haskell是一種懶惰的語言(*)。在計算中,您不需要使用trace1trace2,因此它們不會被評估,也不會被打印。

例如,如果您有

let is = take 4 $ iterate s trace1 

然後trace1將被用來取代

let is = take 4 $ iterate s i 

,應引起跟蹤消息。

(*)更準確地說,GHC的Haskell的實現今天最常用的,使用懶評價,實現Haskell的非嚴格語義。沒關係,如果這沒有意義。