Haskell运行时错误:错误:Prelude。(!!):索引太大

时间:2013-03-14 02:58:55

标签: function haskell runtime-error list-comprehension

我在Haskell中有一个冗长而略显古怪的功能。

(#==#) :: String -> String -> Bool
str1 #==# str2 = (sum[ 1 | index <- [0..(max (length str1) (length str2))], (str1!!index == str2!!index || str1!!index == '$')] == (max (length str1) (length str2)))

简而言之,此函数检查两个字符串是否相同,如果它们有一个或多个'$',则认为它们相同 [长版本:为了节省您解密它的时间,它需要两个字符串,列表解析中的索引变量从0到最长字符串的长度。然后将当前索引处的每个String的元素与彼此或美元符号进行比较。两者都可以。如果它们是其中之一,则将1添加到新列表中,如果此新列表的总和等于长度,则该单词是匹配的。

当我尝试运行时,我得到一个特殊的错误:

*Practice> let totals = (sum[ 1 | index <- [1..(max (length str1) (length str2))], (str1!!index == str2!!index || str1!!index == '$')] == (max (length str1) (length str2)))
*Practice> totals
*** Exception: Prelude.(!!): index too large

我一直在做研究,但没有找到任何解决这个特殊错误的方法。如果有人知道任何事情,我会非常感激。

(顺便说一句,错误中的“索引”与我在函数中使用的索引不同)

1 个答案:

答案 0 :(得分:12)

回到!!执行此任务表明您正试图将另一种语言用于Haskell。请允许我指出更多Haskelly解决方案。据我所知,这个函数执行标准字符串相等测试,但第一个字符串允许有一个字符$,这是一个可以匹配任何单个字符的“通配符”。

回想一下,Haskell中的String只不过是Char的列表。因此,我们可以在两个列表构造函数上进行模式匹配:空列表和非空列表。对两个列表的两种可能性进行匹配为我们提供了四种可能的组合:

(#==#) :: String -> String -> Bool
[]     #==# []     = ???
(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???
(x:xs) #==# (y:ys) = ???

考虑两个列表是否为空。他们匹配吗?让我们说,确实,他们这样做。这是一个重要的基本案例选择,但是现在我只是诉诸于将空字符串放入原始代码的事实应该产生True

[] #==# [] = True

让我们看看中间的两种情况,其中一个列表为空,但另一个列表不是。

(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???

您从未指定长度不均匀的列表会发生什么。但是,为了保留似乎是原始算法的内容,如果第一个列表填充了$,那么我们称之为好,否则,它不匹配。因此,我们将检查左侧列表的第一个元素,如果它是$,那么我们将继续检查列表的其余部分。

('$':xs) #==# []    = xs #==# []
(x:xs)   #==# []    = False
[]       #==# (_:_) = False

让我们看看有趣的案例,两者都是非空的。

(x:xs) #==# (y:ys) = ???

如果左手第一个字符是$,那么我们忽略任何正确的字符,并继续检查。如果绑定到xy的字符相等,那么我们会继续检查。如果它们不相等,那么我们停在False

('$':xs) #==# (_:ys) = xs #==# ys
(x:xs) #==# (y:ys)
  | x == y    = undefined {- exercise to the reader -}
  | otherwise = False

这种技术使用原始递归,而不是列表推导。如果这对您来说似乎很陌生,那么我强烈建议您查看LYAH > Recursion以了解Haskell方式的好介绍。