Неисчерпывающие шаблоны в функции

У меня проблема с этим кодом, он должен считать самую длинную подстроку одной буквы в строке, но есть ошибка:

*** Exception: test.hs:(15,0)-(21,17): 
Non-exhaustive patterns in function countLongest'

Я знаю, что это проблема неправильных типов, но я не знаю, где ошибка, или как ее найти или отладить.

countLongest :: (Eq a) => [a] -> Int
countLongest' :: (Eq a) => Int -> Int -> [a] -> Int

countLongest a = countLongest' 0 0 a
countLongest' n max (y:x:ys)
        | y == x = countLongest' (n+1) max (x:ys)
        | n > max = countLongest' 0 (n) (x:ys)
        | otherwise = countLongest' 0 (max) (x:ys)
countLongest' n max []
        | n > max = n
        | otherwise = max

Ответы

Ответ 1

Похоже, что вам не хватает случая, когда есть один список элементов:

countLongest' n max (y:ys)
    | ... etc. ...
    | otherwise = ....

Здесь надуманный пример, похожий на ваш:

f [] = 3         -- matches an empty list
f (a:b:bs) = 4   -- matches a list with at least two elements

Примеры:

Prelude> :load myfile.hs 
[1 of 1] Compiling Main             ( myfile.hs, interpreted )
Ok, modules loaded: Main.
*Main> f [3]
*** Exception: myfile.hs:(3,0)-(4,13): Non-exhaustive patterns in function f

*Main> f []
3
*Main> f [1,2,3,4,5]
4
*Main> 

Таким образом, он преуспевает с 0 и 2 элементами в списке, но терпит неудачу, когда имеется ровно один элемент.


Обратите внимание, что это поведение не уникально для списков. Здесь пример с использованием Maybe:

g :: Maybe x -> x
g (Just x) = x

Примеры:

*Main> g (Just 4)
4
*Main> g Nothing 
*** Exception: myfile.hs:6:0-13: Non-exhaustive patterns in function g

Это произошло потому, что существуют два конструктора для Maybe, Just <something> и Nothing. Мы не представили случай для Nothing, поэтому, когда мы передали это в g, это не сработало!


Просмотрите этот вопрос и его ответы на информацию о получении небольшой помощи от компилятора. Я последовал совету первого ответа, и когда я загрузил свои примеры, это произошло:

prompt$ ghci -fwarn-incomplete-patterns

Prelude> :load myfile.hs 
[1 of 1] Compiling Main             ( myfile.hs, interpreted )

myfile.hs:3:0:
    Warning: Pattern match(es) are non-exhaustive
             In the definition of `f': Patterns not matched: [_]

myfile.hs:6:0:
    Warning: Pattern match(es) are non-exhaustive
             In the definition of `g': Patterns not matched: Nothing
Ok, modules loaded: Main.

Круто! Компилятор довольно умный!

Ответ 2

Проблема в том, что вам нужно сопоставить, если в рекурсии осталось 1 элемент, например:

countLongest' n max (y:ys)

Поскольку первый из них совпадает, если осталось два или более элемента, а последние совпадают только в том случае, если элемент отсутствует.