【问题标题】:Haskell Runtime Error: error: Prelude.(!!): index too largeHaskell 运行时错误:错误:前奏曲。(!!):索引太大
【发布时间】:2013-03-14 02:58:54
【问题描述】:

我在 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 到最长字符串的长度。然后将当前索引处的每个字符串的元素与彼此或美元符号进行比较。两者都可以。如果它们是其中之一,则将 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

我一直在研究,但没有找到任何解决此特定错误的方法。如果有人对此有所了解,我将不胜感激。

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

【问题讨论】:

  • i 去最长字符串的长度是吗?那么当您尝试在大索引处取消引用较短的索引时会发生什么?
  • 另外,最后一个有效索引是length list - 1
  • @Imray,用两个不同长度的字符串试试...
  • !! 是将索引错误从其他语言移植到 Haskell 的有效方法。 (该代码看起来很像一个转换为列表理解的 for 循环。)

标签: function haskell runtime-error list-comprehension


【解决方案1】:

在此任务中退回!! 表明您正在尝试将另一种语言硬塞到 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 方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    • 2017-01-21
    • 2023-03-25
    • 1970-01-01
    • 2019-05-17
    相关资源
    最近更新 更多