Haskell 包含head和tail函数的函数抛出空列表错误

Haskell 包含head和tail函数的函数抛出空列表错误,haskell,functional-programming,Haskell,Functional Programming,我正在尝试解决中的第一个问题,并提出以下解决方案来计算所需的值: checkRepetition :: [Int] -> Bool checkRepetition [] = False checkRepetition (x:xs) | x == ( head xs ) = True | otherwise = False test :: [Int] -> Int test [] = 0 test [x] = 0 test xs | checkRepetition xs ==

我正在尝试解决中的第一个问题,并提出以下解决方案来计算所需的值:

checkRepetition :: [Int] -> Bool
checkRepetition [] = False
checkRepetition (x:xs)
 | x == ( head xs ) = True
 | otherwise = False

test :: [Int] -> Int
test [] = 0
test [x] = 0
test xs
 | checkRepetition xs == True = ((head xs)*a) + (test (drop a xs))
 | otherwise = test (tail xs)
  where
   a = (go (tail xs)) + 1
   go :: [Int] -> Int
   go [] = 0
   go xs
    | checkRepetition xs == True = 1 + ( go (tail xs) )
    | otherwise = 0
但是,当我给出一个包含重复数字的输入时,例如
[1,3,3]
,它会给出错误

***例外:前奏曲。标题:空列表

然而,有1.5个小时,我无法准确地找出这个错误是在哪里产生的。我的意思是,在
test
函数中使用的任何函数都有
[]
的定义,但它仍然抛出此错误,那么问题是什么

请注意,我已经签出了问题,在给出的答案中,建议不要使用
head
tail
函数,但我已经测试了这些函数的各种输入,它们不会抛出任何错误,那么到底是什么问题呢


我将非常感谢任何帮助或提示。

正如评论中指出的,问题在于:

checkRepetition (x:xs)
 | x == ( head xs ) = True
xs
不能保证是非空列表(一个元素列表被写为
x:[]
,因此
(x:xs)
模式匹配
xs=[]
),在空列表上调用
head
是一个运行时错误

您可以通过将模式更改为仅匹配2+元素列表来处理此问题

checkRepetition []        = False
checkRepetition [_]       = False
checkRepetition (x1:x2:_) = x1 == x2
-- No need for the alternations on this function, by the way.

也就是说,您的算法似乎不必要地复杂。您所要做的就是检查下一个值是否相等,如果相等,则将当前值添加到总数中。假设您可以自己获得<<代码> String > [INT] ,请考虑如下类似的内容:

filteredSum :: [Int] -> Int
filteredSum []            = 0  -- by definition, zero- and one-element lists
filteredSum [_]           = 0  -- cannot produce a sum, so special case them here
filteredSum xss@(first:_) = go xss
  where
  -- handle all recursive cases
  go (x1:xs@(x2:_)) | x1 == x2   = x1 + go xs
                    | otherwise  =      go xs
  -- base case
  go [x]            | x == first = x  -- handles last character wrapping
                    | otherwise  = 0  -- and if it doesn't wrap
  -- this should be unreachable
  go []             = 0
不管它值多少钱,我认为最好在Maybe monad中工作,并在
Maybe[Int]->Maybe Int
上操作,但幸运的是,这很容易,因为Maybe是一个函子

digitToMaybeInt :: Char -> Maybe Int
digitToMaybeInt '0' = Just 0
digitToMaybeInt '1' = Just 1
digitToMaybeInt '2' = Just 2
digitToMaybeInt '3' = Just 3
digitToMaybeInt '4' = Just 4
digitToMaybeInt '5' = Just 5
digitToMaybeInt '6' = Just 6
digitToMaybeInt '7' = Just 7
digitToMaybeInt '8' = Just 8
digitToMaybeInt '9' = Just 9
digitToMaybeInt _   = Nothing

maybeResult :: Maybe Int
maybeResult = fmap filteredSum . traverse digitToMaybeInt $ input

result :: Int
result = case maybeResult of
         Just x  -> x
         Nothing -> 0
-- this is equivalent to `maybe 0 id maybeResult`

谢谢你的链接。我先去那里了解目的。 我假设输入将是一个字符串。下面的helper函数构造一个数字列表,用于在谓词为True时求和,即压缩值相等,即每个数字与每个连续数字(成对)进行比较

辅助函数“nl”使用数字列表调用主函数“invcap”反向验证码

nl函数是一个列表理解函数。invcap函数是一个列表理解函数。也许这个问题的逻辑是错误的。过于复杂的逻辑更容易引入错误。当逻辑不麻烦时,证明就容易多了

主要功能“invcap”


invcap l=sum[x |(x,y)如果你给它传递一个单例列表,比如
[4]
。你在
xs
@WillemVanOnsem上调用
tail
,我得到的只是一个空列表。@WillemVanOnsem,当我在ghci上尝试它时,它确实会抛出任何错误。直接的问题是
检查重复
,所以你应该测试该函数是否执行了它应该执行的操作。不过,更一般来说,问题是你不应该这样做使用
head
tail
。只需使用模式匹配。此外,
foo==True
foo
@onurcanbektas Willem引用的列表
[2]
将导致对
2==head[]的评估
,这就是错误的来源。请使用模式匹配,而不是使用
head
tail
(模式可以是任意复杂的–
x:y:xs
匹配至少包含两个元素的列表。)您的“修复”
checkrepeation
对单身列表仍然不起作用…@DanielWagner哎哟,疏忽。修复。感谢你的回答@AdamSmith;然而,尽管我很欣赏这种情绪,但发布我试图解决的主要问题的解决方案阻止我阅读你的答案:)仅供参考,显然我误解了这个问题em,所以在意识到这一点后,我得到了与您几乎完全相同的答案。这处理单例输入。>nl“1”…1''''''''''''invcap[2]…2''''''''invcap[]..0--此函数将任何输入列表分成两个列表,因此在无考虑的输入下继续工作。
invcap l = sum [ x | (x,y) <- zip l $ (tail l) ++ [head l], x == y]
nl cs = invcap [ read [t] :: Int | t <- cs]