2011-09-11 32 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的非严格语义。没关系,如果这没有意义。