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

Cod*_*ein 1 haskell runtime-error list-comprehension function

我在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)))
Run Code Online (Sandbox Code Playgroud)

简而言之,这个函数检查两个字符串是否相同,并且如果它们有一个或多个'$'则认为它们是相同的 [长版本:为了节省您解密它的时间,它需要两个字符串,列表理解中的索引变量从0到最长String的长度.然后将当前索引处的每个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
Run Code Online (Sandbox Code Playgroud)

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

(顺便说一下,错误中的"索引"与我在函数中使用的索引不一样)

Dan*_*ton 12

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

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

(#==#) :: String -> String -> Bool
[]     #==# []     = ???
(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???
(x:xs) #==# (y:ys) = ???
Run Code Online (Sandbox Code Playgroud)

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

[] #==# [] = True
Run Code Online (Sandbox Code Playgroud)

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

(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???
Run Code Online (Sandbox Code Playgroud)

您从未指定长度不均匀的列表会发生什么.但是,为了保留看起来像你的原始算法,如果第一个列表被填充,$那么我们称之为好,否则,它不匹配.所以我们将检查左侧列表的第一个元素,如果是,$那么我们将继续检查列表的其余部分.

('$':xs) #==# []    = xs #==# []
(x:xs)   #==# []    = False
[]       #==# (_:_) = False
Run Code Online (Sandbox Code Playgroud)

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

(x:xs) #==# (y:ys) = ???
Run Code Online (Sandbox Code Playgroud)

如果左手第一个字符是$,那么我们忽略任何正确的字符,并继续检查.如果字符绑定x并且y相等,那么我们继续检查.如果他们不平等,那么我们就停止了False.

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

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