为什么我会在这里遇到“索引太大”的异常?

时间:2014-12-18 17:58:58

标签: list exception haskell indexing

我试图编写一个返回重复元素的函数

findMul :: [String] -> String
findMul [] = []
findMul s
    |ss!!0 == ss!!1 = ss!!0
    |otherwise    = findMul (tail s)
    where
    ss = sort s

sort :: [String] -> [String]
sort [] = []
sort (x:ys) = (sort ls) ++ [x] ++ (sort gs)

    where       
    ls = [y | y<-ys, y<=x]
    gs = [y | y<-ys, y>x ]

使用输入

进行测试时,这似乎有效
findMul ["d","c","b","a","a"]

正确返回

"a"

但是当我用稍微不同的输入进行测试时

findMul ["d","c","b","b","a"]

返回错误

*** Exception: Prelude.(!!): index too large

任何人都可以解释错误的含义吗?可能为什么会这样?

3 个答案:

答案 0 :(得分:2)

您的sort功能没问题;问题在于findMul函数的定义。注意第二种模式,

findMul s
如果列表s非空,则使用

。特别是,在s的情况下使用的是单例列表(仅由一个元素组成的列表)。

此外,列表sss的长度始终相同;因此,如果s只有一个元素,ss也只有一个元素。

但是,在ss!!1中,您尝试访问ss第二个元素,如果s是单例列表,则存在。您实际上是在尝试访问超出列表ss的实际长度(即1)的元素!这就是Haskell对你大吼大叫的原因:

*** Exception: Prelude.(!!): index too large

答案 1 :(得分:1)

findMul的模式匹配可以采用单个元素列表

findMul ["b"]

发生这种情况时,ss列表的长度也为1,但您在守护ss!!1中使用其中的第二个元素。

这是错误。

答案 2 :(得分:1)

使用!进行列表访问通常不是最好的主意。使用模式匹配,事情变得更加清晰。

findMul (x:y:rest) = if x == y then y else findMul (y:rest)  
findMul [x] = x  -- the branch you originally missed 
findMul [] = undefined -- or what you'd prefer

很明显,您只能找到第一次重复。考虑完整的RLE:)