Предупреждение о сопоставлении шаблонов Haskell

#haskell

#haskell

Вопрос:

я относительно новичок в Haskell (третий день изучаю язык), и у меня возникла проблема с сопоставлением шаблонов. Я определил функцию doubleEveryOther ниже, и, насколько я вижу, я рассмотрел три возможных сценария: пустой список, список длины == 1 и длина списка> 1. Код компилируется нормально, но при попытке использовать функцию он выдает неполную ошибку сопоставления с шаблоном:

 *** Exception: ex2.hs:(3,1)-(5,55): Non-exhaustive patterns in function doubleEveryOther
 

Затем я включил предупреждения в GHCI и обнаружил следующее предупреждение при загрузке файла ex2.hs:

 ex2.hs:3:1: Warning:
    Pattern match(es) are non-exhaustive
    In an equation for `doubleEveryOther':
        Patterns not matched: _ : (_ : (_ : _))
 

Строка 3: 1 относится к пустому регистру, который, я думаю, я рассмотрел doubleEveryOther [] = []

Я не могу понять, где я ошибся здесь. Помощь приветствуется.

Ваше здоровье,

 -- file: ex2.hs
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (_:[xs]) = take (length [xs] - 1) [xs]
 

Ответ №1:

Проблема в третьем шаблоне:

 doubleEveryOther (_:[xs])
 

Этот шаблон соответствует случаю списка с двумя элементами (поскольку x:[xs] эквивалентно [x,xs] ). Правильный синтаксис:

 doubleEveryOther (_:xs)
 

Комментарии:

1. Понял. В настоящее время у меня есть шаблоны для пустых, 1 и 2, но не 2 или более. Изменение его на указанное выше дает шаблоны для пустых, 1 и 2 или более. Спасибо. Есть ли у вас какие-либо идеи, почему предупреждение ссылается на строку, содержащую второй шаблон, а не на третий (строка 3, а не 4)? У меня возникли проблемы с исправлением моего кода с помощью предупреждающих сообщений, и это, вероятно, важный фактор.

2. @Dave0504 Я думаю, что это просто относится к первой строке сопоставления с образцом. Обратите внимание, что в предупреждении GHC он дает весь диапазон: (3,1) — (5,55)

Ответ №2:

Строка

 doubleEveryOther (_:[xs]) = take (length [xs] - 1) [xs]
 

соответствует списку из двух элементов, то есть несвязанному заголовку, за которым следует одноэлементный список, содержащий элемент xs . Вы должны использовать

 doubleEveryOther (_:xs) = take (length xs - 1) xs
 

вместо take (n-1) того, чтобы вы можете использовать drop 1 :

 doubleEveryOther (_:xs) = drop xs
 

или использование сопоставления:

 (_:_:xs) = xs
 

Вероятно, в этом случае вы также захотите выполнить рекурсивный вызов.