2013-03-08 60 views
2

我的代码抛出一个空列表错误。当我运行:Haskell Prelude.head错误,空列表

makeAgent :: Agent -> [Agent] -> Agent 
makeAgent (Agent func n _) agents = (Agent func (n++(show $ length $ sameNames n agents)) empty) --appends number to name to differentiate agents 
    where sameNames n agents = filter (findName n) agents 
      findName n1 (Agent _ n2 _) = (slice 0 3 n1) == (slice 0 3 n2) --ignore the suffix 
      empty = head $ getEmpty (positions agents) (fst $ getGrid agents) --getGrid returns a tuple, but currently assume to be a square 

baseline :: [Interaction] -> Float 
baseline int = (fromIntegral total)/len 
    where total = sum sums 
     sums = map snd (showSums int) 
     agents = nub $ map (\(Interaction a1 a2 _) -> a2) int 
     len = fromIntegral $ length agents 

reproduce :: Float -> [Interaction] -> [Agent] --so baseline isn't recalulated every time 
reproduce _ [] = [] 
reproduce base interaction = winners ++ [newAgent] ++ reproduce base (tail interaction) 
    where agents = nub $ concat $ map (\(Interaction a1 a2 _) -> a1:a2:[]) interaction 
      winners = [a | a <- agents, (sumAgent interaction a) >= (round base)] 
      newAgent = makeAgent (head winners) winners 


main = do 
    output "Length" (fromIntegral $ length int) 
    output "Baseline" base 
    output "Agents" agents 
    output "Sums" (showSums int) 
    output "winners" winners 
    output "NeAgent" (makeAgent (head winners)winners) 
    output "New Agents" (reproduce base int) 

    where agents = generate 4 
      int = playRound agents 20 
      base = baseline int 
      winners = [a | a <- agents, (sumAgent int a) >= (round base)] 

这是什么重现,主要功能,应该做的根据自己的父母“全民健身”是否超过一定水平时产生一个新的代理,然后用所有,但有运行相同的功能代理列表中的代理。

它输出:

Length: 16 
Baseline: 280.0 
Agents: [c_pavlov(-1,-1),c_titForTat(-1,0),c_sucker(-1,1),b_grim(0,-1)] 
Sums: [("c_pavlov",280),("c_titForTat",280),("c_sucker",280),("b_grim",280)] 
winners: [c_pavlov(-1,-1),c_titForTat(-1,0),c_sucker(-1,1),b_grim(0,-1)] 
NeAgent: c_pavlov1(0,0) 
prisoners: Prelude.head: empty list 

当我打电话重现,它抛出prelude.head空列表错误,获奖者,代理人,和int列表是所有非空的,所以它可能是一个边缘在递归的最后一次迭代中出现大小写错误。这是为什么发生?

+0

您不会向我们展示打印“囚犯”的行 – Ingo 2013-03-08 09:45:57

+0

不是文件的名称,所以这就是它在错误发生之前的前缀。 – MichaelFine 2013-03-08 21:37:48

+0

请提供完整的信息来源。 – 2013-03-10 16:58:18

回答

1

您并没有完全说出错的发生位置。大概是当你拨打tailhead而不检查列表是否为空。

如果是这种情况,您可以使用模式匹配修复空的interaction列表。

否则,您需要提供有关错误的更多信息。

(编辑:与头替换尾部)

+0

正弦错误是'Prelude.head'我不得不说这不太可能 – 2013-03-08 04:24:44

+0

啊!我正在寻找原始文章中的错误消息,但没有看到它。尽管如此,建议(使用模式匹配)仍然保持不变,尽管在kosmikus的回答中更充分地表达了这一点。 – 2013-03-08 12:33:29

8

的解决方案是相对比较简单:只需不Haskell程序使用headtail。 (虽然有几种情况这样做是合理的,但最好在开始时假设没有。)

而是使用模式匹配。通常情况下,你要一直都空列表和非空列表上正常模式匹配,就像这样:

fun :: [Something] -> ... 
fun []  = ... 
fun (x : xs) = ... -- x is head, xs is tail 

这样,你不得不处理错误,你知道参考xxs不能再失败,因为该列表已被确定为非空。

如果您的程序中有很多列表不应该为空,那么您必须手动跟踪这些条件(并且至少应该有文档他们)。但即便如此,它在一个let - 结合更好的模式匹配这样

(winner : _) = ... 

,然后参考winner该名单中的后头,因为你会得到涉及的行号,该模式的错误信息比赛失败。