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

#haskell #recursion #non-exhaustive-patterns

#haskell #рекурсия #неисчерпывающие-шаблоны

Вопрос:

Я пытаюсь написать функцию, которая дает мне расстояние между каждым районом в моем списке. Функция distance дает мне расстояние между двумя районами как Int из заданного массива, и я хочу просмотреть весь список, чтобы суммировать расстояние между каждым районом и его последователем в списке.

Но я получаю

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

сообщение об ошибке. Что я упустил из виду? Функция distance работает так, как должна.

 lengthr :: [district] -> Int
lengthr [] = 0
lengthr (a:b:as) = (distance a b)   lengthr (b:as) 
 

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

1. Что должно произойти, если вы предоставите lengthr список, содержащий ровно один элемент?

2. Следующего пункта назначения для перехода не будет, поэтому расстояние должно выводить 0.

3. Видите ли вы какие-либо строки в вашем текущем определении функции, которые могли бы это сделать? Если нет, можете ли вы придумать строку, которую вы могли бы добавить?

4. В будущем компилируйте с предупреждениями об использовании -Wall : вы обнаружите ошибку во время компиляции, и в сообщении об ошибке будут указаны случаи, которые вы упускаете.

Ответ №1:

Я добавил строку lengthr [a] = 0 в свой код, чтобы скрыть случай, когда остался только один элемент, и теперь код работает так, как задумано!

Ответ №2:

Как вы упомянули в своем собственном ответе, вы упустили случай одного элемента.

Более общим решением является включение всеобъемлющего шаблона _ после всех конкретных случаев, которые вы хотите обработать.

 lengthr:: [district] -> Int
lengthr (a:b:as) = (distance a b)   lengthr (b:as)
lengthr _ = 0
 

Это более традиционный способ обработки ситуаций по умолчанию.

В ситуациях, когда результат содержится в a Monad , который имеет семантику ошибки (например, Either e и Maybe ), вы можете сделать случай по умолчанию ошибкой вместо того, чтобы потенциально игнорировать ошибку.

 lengthr:: [district] -> Either String Int
lengthr (a:b:as) = do
  next <- lengthr (b:as)
  Right $ (distance a b)   next
lengthr [_] = Right 0
lengthr _ = Left "empty list"