#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
Вероятно, в этом случае вы также захотите выполнить рекурсивный вызов.